高性能的JavaScript--加载和执行[转]

写在前面

JavaScript在浏览器中的性能,可认为是开发者所要面对的最重要的可用性的问题,此问题因JavaScript的阻塞特征而复杂,也就是说JavaScript运行时其他的事情不能被浏览器处理,事实上,大多数浏览器使用单进程处理UI更新和JavaScript运行等多个任务,而同一时间只能有一个任务被执行。JavaScript运行了多长时间,那么浏览器空闲下来响应用户输入之前的等待时间就有多长。

从基本层面说,这就意味着<script>标签的出现使整个页面因脚本解析、运行出现等待。不论实际的JavaScript代码是内联的还是包含在一个不相干的外部文件中页面下载和解析过程必须停下,等待脚本完成这些处理,然后才能继续,也是页面生命周期必不可少的部分,因为脚本可能在运行过程中修改页面内容。

在加载JavaScript过程中,页面解析和用户交互是被完全阻塞的。

脚本位置

HTML 4 文档指出,一个<script>标签可以放在 HTML文档的 <head> 或者<body>标签中,可以在其中多次出现。传统上,<script> 标签用于加载外部JavaScript 文件。<head>部分除此类代码外,还包含 <link>标签用于加载外部css文件和其他页面中间件。也就是说,最好把风格和行为所依赖的部分放在一起,首先加载他们,使他们可以得到正确的外观和行为。

例如:

 1 <html>
 2 <head>
 3 <title>Script Example</title>
 4 <-- Example of ineffi cient script positioning -->
 5 <script type="text/javascript" src="file1.js"></script>
 6 <script type="text/javascript" src="file2.js"></script>
 7 <script type="text/javascript" src="file3.js"></script>
 8 <link rel="stylesheet" type="text/css" href="styles.css">
 9 </head>
10 <body>
11 <p>Hello world!</p>
12 </body>
13 </html>

虽然这些代码看起来没什么问题,但是在〈head〉部分加载了三个JavaScript文件。每个〈script〉标签阻塞了页面解析过程,直到完整的下载并运行了外部JavaScript代码之后,页面才能继续进行。在浏览器没有遇到〈body〉标签之前,不会渲染页面的任何部分。

把脚本放在页面的顶端,将会导致一个可以察觉的延迟,通常表现为:页面打开一片白,用户不能阅读和操作。

如图,当第一javas文件开始下载时,阻塞了其他文件下载。进一步当第一个文件下载完成之后和第二个文件下载之前有一个延时,是第一个文件完全运行所需要的时间。

解决这个问题推荐的办法是:将所有<script> 标签放在尽可能接近<body> 标签的底部位置,尽量减少对整个页面下载的影响。

如:

 1 <html>
 2 <head>
 3 <title>Script Example</title>
 4 <link rel="stylesheet" type="text/css" href="styles.css">
 5 </head>
 6 <body>
 7 <p>Hello world!</p>
 8 <-- Example of recommended script positioning -->
 9 <script type="text/javascript" src="file1.js"></script>
10 <script type="text/javascript" src="file2.js"></script>
11 <script type="text/javascript" src="file3.js"></script>
12 </body>
13 </html>

组成脚本

由于每个<script>标签下载时阻塞页面解析过程,所以限制页面的<script>总数也是可以改善性能。这个规则对内联脚本和外部脚本同样适用。每当页面解析碰到一个<script>标签时,紧接着有一段时间用于代码执行。最小化这些延迟时间可以改善页面的整体性能。

每个HTTP请求都会产生额外的性能负担,下载一个100KB的文件比下载4个25KB的文件要快。总之,减少引用外部文件的数量。典型的,一个大型网站或者网页应用需要多次请求JavaScript文件。你可以将这些文件整合成一个文件,只需要一个<script>标签引用,就可以减少性能损失。

非阻塞脚本

JavaScript倾向于阻塞浏览器某些处理过程,如HTTP请求和界面刷新,这是开发者面临的最显著的性能问题。保持JavaScript文件短小,并限制HTTP请求的数量,只是创建反应迅速的网页应用的第一步。一个应用程序所包含的功能越多,所需要的JavaScript代码就越大,保持源码短小并不总是一种选择。尽可能下载一个大JavaScript文件只产生一次HTTP请求。却会锁住浏览器一大段时间。为避开这种情况,你需要向页面中逐步添加JavaScript,某种程度上说不会阻塞浏览器。

非阻塞脚本的秘密在于,等页面加载之后,再加载JavaScript源码。从技术角度上讲,这意味着在window的load事件发出之后下载代码。有几种方法可以实现这种效果。

1.延期脚本

HTML4为<script>标签定义了一个扩展属性:defer。这个defer属性指明元素中所包含的脚本不打算修改DOM,因此代码可以稍后执行(适用于IE4以上浏览器)

<script type="text/javascript" src="file1.js" defer></script>

带有该属性的JavaScript文件在<script>被解析时启动下载,但代码不会被执行,直到DOM加载完成,它不会阻塞浏览器的其他处理过程,所以这些文件可以与页面的其他资源一起并行下载。
2.动态脚本元素

文档对象模型dom允许使用JavaScript动态创建HTML的几乎全部文档内容。其根本在于<script>元素与页面其他元素没有什么不同。
 当文件使用动态脚本节点下载时,返回的代码通常立即执行。当脚本“自运行”类型时这一机制运行正常,但是如果脚本只包含页面其他脚本调用的的接口,则会带来问题。这种情况下,你需要跟踪脚本下载完成并准备妥善的情况。
IE 会发出一个readystatechange事件。<script>元素有一个readyState属性,它的值随着外部下载的过程而改变。readyState有5种取值。
uninitialized       默认状态
loading             开始下载
interactive        下载完成但尚不可用
complete          所有数据都已经准备好

下面封装一个函数来实现JavaScript文件的动态加载:

 1 function loadScript (url, callback){
 2 var script = document.createElement ("script")
 3 script.type = "text/javascript";
 4 if (script.readyState){ //IE
 5 script.onreadystatechange = function(){
 6 if (script.readyState == "loaded" ||  script.readyState == "complete"){
 7 script.onreadystatechange = null;
 8 callback();
 9 }
10 };
11 } else {  //Others
12 script.onload = function(){
13 callback();
14 };
15 }
16 script.src = url;
17 document.getElementsByTagName_r("head")[0].appendChild(script);
18 }

使用方法:

1 loadScript("file1.js", function(){
2 alert("File is loaded!");
3 }); 

使文件按顺序加载:

1 loadScript("file1.js", function(){
2 loadScript("file2.js", function(){
3 loadScript("file3.js", function(){
4 alert("All files are loaded!");
5 });
6 });
7 });

3.XHR脚本注入
使用XMLHttpRequest(XHR)对象将脚本注入到页面中。此技术首先创建一个XHR对象,然后下载javas文件,接着用一个动态<script>元素将javas代码注入页面。

 1 var xhr = new XMLHttpRequest();
 2 xhr.open("get", "file1.js", true);
 3 xhr.onreadystatechange = function(){
 4 if (xhr.readyState == 4){
 5 if (xhr.status >= 200 && xhr.status < 300 | | xhr.status == 304){
 6 var script = document.createElement ("script");
 7 script.type = "text/javascript";
 8 script.text = xhr.responseText;
 9 document.body.appendChild(script);
10 }
11 }
12 };
13 xhr.send(null);

此代码向服务器发送一个获取file1.js文件的GET请求。onreadystatechange事件处理函数检查readyState是不是4,然后检查HTTP状态码是不是有效(2XX表示有效回应,304表示一个缓存响应)。如果收到一个有效的响应,那么就创建一个新的<script>元素,将它的文本属性设置为从服务器接受到的resposeText字符串。这样做实际上会创建一个带有内联代码的<script>元素。一旦新的<script>元素被添加到文档,代码将被执行并准备使用。

这种方法的主要优点是,您可以下载不立即执行的 JavaScript 代码。由于代码返回在<script>标签之外(换句话说不受<script>标签约束),它下载后不会自动执行,这使得您可以推迟执行,直到一切都准备好了。另一个优点是,同样的代码在所有现代浏览器中都不会引发异常。

此方法最主要的限制是:JavaScript 文件必须与页面放置在同一个域内,不能从 CDN 下载(CDN 指”内容投递网络(Content Delivery Network)”,所以大型网页通常不采用 XHR 脚本注入技术。

总结

减少 JavaScript 对性能的影响有以下几种方法:

  • 将所有的<script>标签放到页面底部,也就是</body>闭合标签之前,这能确保在脚本执行前页面已经完成了渲染。
  • 尽可能地合并脚本。页面中的<script>标签越少,加载也就越快,响应也越迅速。无论是外链脚本还是内嵌脚本都是如此。
  • 采用无阻塞下载 JavaScript 脚本的方法:
  • 使用<script>标签的 defer 属性(仅适用于 IE 和 Firefox 3.5 以上版本);
  • 使用动态创建的<script>元素来下载并执行代码;
  • 使用 XHR 对象下载 JavaScript 代码并注入页面中。

高性能的JavaScript--加载和执行[转]

时间: 2024-10-29 19:10:41

高性能的JavaScript--加载和执行[转]的相关文章

怎么样加快JavaScript加载和执行效率

概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器在下载和执行脚本时出现阻塞的原因在于,脚本可能会改变页面或 JavaScript 的命名空间,它们对后面页面内容造成影响.一个典型的例子就是在页面中使用document.write(). JavaScript 代码内嵌示例 <html> <head> <title>Source

加快JavaScript加载和执行效率

JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就是说当浏览器在执行 JavaScript 代码时,不能同时做其他任何事情.本文详细介绍了如何正确的加载和执行 JavaScript 代码,从而提高其在浏览器中的性能. 概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器

JavaScript加载与执行

多数情况下,浏览器是用单一进程处理用户界面和JavaScript脚本执行.所以,JavaScript的处理时间越久,浏览器等待响应事件就越长. 简单地说,就是浏览器每次处理<script>标签,就会让页面等待脚本的解析和执行.这个过程页面渲染和用户交互是完全阻塞的. 一.脚本位置 H4规范指出,<script>标签可以放在<head>和<body>标签内,并允许出现多次. 1.1 将脚本放在底部 正常情况下,多个脚本放到<head>内,浏览器会一

高性能JavaScript 加载和执行

前言 本章主要讲述如何加载脚本使得用户能有良好的用户体验,而核心内容就是JavaScript的异步加载.之前写过一篇不得不说的JavaScript异步加载,相似的内容就不多加描述,讲些不同的东西,主要讲下JavaScript文件加载器labjs的常用方法. 流水账 脚本位置:推荐将所有的<script>标签尽可能放到<body>标签的底部,也就是</body>之前,这样就能在执行js代码之前将用户界面呈现出来,改善用户体验. 组织脚本:由于每个<script>

[转]JavaScript 的性能优化:加载和执行

原文链接:http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/index.html?ca=drs- JavaScript 的性能优化:加载和执行 蔡 愉晟, 软件工程师, IBM 简介: 随着 Web2.0 技术的不断推广,越来越多的应用使用 JavaScript 技术在客户端进行处理,从而使 JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就

【转】js JavaScript 的性能优化:加载和执行

JavaScript 的性能优化:加载和执行 转自:https://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/ 随着 Web2.0 技术的不断推广,越来越多的应用使用 JavaScript 技术在客户端进行处理,从而使 JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就是说当浏览器在执行 JavaScript 代码时,不能同时做其他任何事情.本文详

JavaScript 的性能优化:加载和执行

随着 Web2.0 技术的不断推广,越来越多的应用使用 JavaScript 技术在客户端进行处理,从而使 JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就是说当浏览器在执行 JavaScript 代码时,不能同时做其他任何事情.本文详细介绍了如何正确的加载和执行 JavaScript 代码,从而提高其在浏览器中的性能. 概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必

浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入

在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及其他的细节问题.而除了defer和async特性,动态脚本和Ajax脚本注入也是两种常用的创建无阻塞脚本的方法.总的来看,这两种方法都能达到脚本加载不影响页面解析和渲染的作用,但是在不同的浏览器中,这两种技术所创建的脚本的执行时机还是有一定差异,今天我们再来探讨一下通过动态脚本技术和Ajax注入的脚本在这些方

JavaScript的性能优化:加载和执行

随着 Web2.0 技术的不断推广,越来越多的应用使用 javascript 技术在客户端进行处理,从而使 JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就是说当浏览器在执行 JavaScript 代码时,不能同时做其他任何事情.本文详细介绍了如何正确的加载和执行 JavaScript 代码,从而提高其在浏览器中的性能. 1.概述 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染

JavaScript之jQuery-4 jQuery事件(页面加载后执行、事件处理、事件冒泡、事件对象、模拟操作)

一.jQuery 页面加载后执行 代码执行的时机选择 - $(document).ready()方法和 window.onload事件具有相似的功能,但是在执行时机方面是有区别的 - window.onload 事件是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行 - $(document).ready()方法注册的事件处理程序,在DOM完全加载后就可以调用 - 一般来讲, $(document).ready()的执行要优于window.onload事件 - 需要注意的是,