JavaScript 在浏览器中的性能,可以认为是开发者所面临得最严重的可用性问题。这个问题因JavaScript的阻塞特性变得复杂,

也就是说当浏览器在执行JavaScript代码时,不能同时做其他任何事情

多数浏览器使用单一进程来处理用户界面(UI)的刷新和JavaScript脚本执行,所以同一时刻只能做一件事。

JavaScript执行过程耗时越久,浏览器等待响应的时间就越长。

每次<script>标签出现都霸道的让页面等待脚本的解析和执行。

脚本位置

  将脚本放在底部:推荐将所有的<script>标签尽可能的放到<body>标签的底部,以尽量减少对整个页面下载的影响

  

脚本数量

  限制内嵌脚本的数量:由于每个<script>标签初始下载时都会阻塞页面渲染,所以减少页面包含的<script>标签数量有助于改善这一情况。这不仅仅针对外链脚本,内嵌脚本的数量也同样需要显示。浏览器在解析HTML页面的过程中没遇到一个<script>标签,都会因执行脚本而导致一定的延时。因此最小化延迟时间将会明显改善页面的总体性能。

  同时Steve Souder还发现,把一段内嵌脚本放在引用外链样式表的<link>标签之后会导致页面阻塞去等待样式表的下载。因此永远不要把内嵌脚本紧跟在<link>标签后面

  另外,下载一个100KB的文件将比下载4个25KB的文件更快。也就是说,减少页面中外链脚本文件的数量将会改善性能。可以把多个文件合并成一个,这样只需要引用一个<script>标签,减少性能消耗。

 无阻塞的脚本

  减少JavaScript文件大小和限制HTTP请求数有时候远远不够,WEB功能越丰富,所需要的JavaScript代码就越多,所以精简源代码并不总是可行,尽管下载单个较大的JavaScript文件只产生了一次HTTP请求,却会锁死浏览器一大段时间。这种情况下需要向页面上逐步的加载JavaScript文件,这样做在某种程度上来说不会阻塞浏览器。

  无阻塞脚本:在页面加载完成后才加载JavaScript代码。意味着在window对象的load事件触发后再下载脚本【defer和async】

 延迟的脚本

HTML4为<script>标签定义了扩展属性:defer。Defer属性指明本元素所含的脚本不会修改DOM,因此代码能安全的执行。该属性只有IE4和Firefox3.5+的浏览器支持,所以它不是一个理想的跨浏览器解决方案。其他浏览器中defer会被直接忽略。

defer受限:低版本IE浏览器不支持,如今所有的主流浏览器都已经实现对defer属性的支持,W3C规定:defer属性仅当src属性声明时才生效。

使用方法:

<script type = "text/javascript" src = "file1.js" defer></script>
或者
<body>
  <script defer>
    alert("defer");
  </script>
  <script>
    alert("script");
  </script>
  <script>
    window.onload = function(){
     alert("load");
    }
  </script>
</body>
//在支持defer的浏览器中,弹出的顺序是“script”,“defer”,“load”。注意:带有defer属性<script>元素不是跟在第二个后边执行,而是在onload事件处理器执行之前被调用

  async:HTML5中引入的async属性,用于异步加载脚本。async与defer都是采用并行下载,在下载过程中不会产生阻塞。

      区别在于执行时机,async是加载完成后自动执行,而defer是需要等待页面完成后执行。

动态脚本元素

由于文档对象模型DOM的存在,可以用JavaScript动态创建HTML中的几乎所有内容。

<script>的元素下载过程中,readyState属性有五种取值,其中“loaded”和“complete”是最常用的状态。

IE在标识最终状态的readyState的值时并不一致,有时候达到loaded状态 ,有时候达到complete状态。所以使用readystatechange事件的最靠谱方式就是同时检查这两种状态,只要触发其中一个就删除事件处理器。(以确保事件不会被处理两次)

下边的函数封装了标准及IE特有的实现方法:

function loadScript(url,callback){
var script = document.creatElement("script");
script.type = "text/script"; if(script.readyState){ //IE
  script.onreadystatechange = function(){
      if(script.readyState == "loaded" || script.readyState == "complete"){
        script.onreadystatechange = null;
        callback();
      }
    }
}else{  //其他浏览器
     script.onload = function(){
        callback();
     }
   }
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
}

如果需要你可以动态加载尽可能多的javaScript文件到页面上,但是一定要考虑文件的加载顺序。在所有主流浏览器中,只有Firefox和Opera能保证脚本会按照你指定的顺序执行,其他浏览器将会按照从服务端返回的顺序下载和执行代码,你可以将下载操作串联起来以保证下载顺序:

loadScript("file1",function(){
loadScript("file2",function(){
loadScript("file3",function(){
alert("All files are loaded!!");
    })
  })
})

弊端:如果需要下载很多的文件,这个方案就会带来一点管理上的麻烦。

  如果多个文件的下载顺序很重要,最好的做法就是把他们按正确的顺序合并成一个文件。下载这个文件就能一次获得所有的代码(这个过程是异步的,文件大一点也不会有影响)

  动态脚本加载凭借着它在浏览器兼容性和易用的优势,成为最通用的无阻塞加载解决方案。

 XMLHttpResquest脚本注入

另一种无阻塞加载脚本的方法是使用XMLHttpResquest(XHR)对象获取脚本并注入页面中。

var xhr = new XMLHttpRequest();
xhr.open("get","file1.js",true);
xhr.onreadystatechange = function(){
if(xhr.readyState == ){
if(xhr.status >= && xhr.status < || xhr.status == ){
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.reaponseText;
document.body.appendChild(script);
}
}
}
xhr.send(null);

发送get请求获取“file1.js”文件,事件处理函数onReadyStateChange检查readyState是否为4,同时校验HTTP状态码是否有效(2XX表示有效响应,304意味着是从缓存读取)

然后创建<script>元素,并设置属性。一旦新创建的元素被添加到页面,代码会立刻执行然后准备就绪。

优点:你可以下载JavaScript代码但不立即执行,由于代码是在<script>标签之外返回的,因此它下载之后不会自动执行,这使得你可以把脚本的执行推迟到你准备好的时候,

   同样的代码在所有主流浏览器中无一例外都能正常工作。

局限性:JavaScript文件必须与所请求的页面处于相同的域,这意味着JavaScript文件不能从CDN上下载,因此大型Web应用不会采用XHR脚本注入技术

推荐的无阻塞模式

向页面添加大量JavaScript的推荐做法只需两步:先添加动态加载所需的代码,然后加载初始化页面所需的剩下的代码。因为第一部分的代码尽量精简,甚至可能只包含loadScript()函数,它下载执行都很快,所以不会对页面有太多影响。一旦初始代码就位,就用它来加载剩余的JavaScript。

<script type="text/javascript" src = "loader.js">
<script type="text/javascript">
loadScript("the-rest.js",function(){
Application.init();
});
</script>

把这段代码放在</body>闭合标签之前。

好处:确保了JavaScript执行过程中不会阻碍页面其他内容的显示。其次,当第二个JavaScript文件完成下载时,应用所需的所有DOM结构已经创建完毕,并做好了交互准备,从而避免了需要另一个事件(比如window.onload)来检测页面是否准备好。

当然可以把loadScript()函数直接嵌入页面,省去了加载<script type="text/javascript" src = "loader.js">时的一次http请求。

 YUI3的方法:没看明白...

 LazyLoad类库

雅虎的工程师创建了一个更为通用的延迟加载工具:LazyLoad(源代码:http://github.com/rgrove/lazyload/)。LazyLoad是loadScript()函数的增强版。

<script type="text/javascript" src = "lazyload.min.js">
<script type="text/javascript">
LazyLoad.js("the-rest.js",function(){
Application.init();
});
</script> //LazyLoad支持下载多个JavaScript文件,需要传入一个URL数组 <script type="text/javascript" src = "lazyload.min.js">
<script type="text/javascript">
LazyLoad.js(["the-rest.js","last-file.js"],function(){
Application.init();
});
</script>

分析:尽管这种无阻塞的方式可以动态加载很多文件,但是建议尽量减少文件数。因为每个文件的下载都是一个独立的http请求,而且回调函数会等待所有文件都下载完成后才会执行

LABjs

LABjs(http://labjs.com)可以进行链式调用

<script type="text/javascript" src = "lab.js">
<script type="text/javascript">
$LAB.script("first-file.js")
     .script("the-rest.js")
     .wait(function(){
        Application.init();
    });
</script>

为了保证first-file.js在the-rest.js的代码前执行,需要再第一个script()方法后调用wait():

<script type="text/javascript" src = "lab.js">
<script type="text/javascript">
$LAB.script("first-file.js").wait()
    .script("the-rest.js")
    .wait(function(){
      Application.init();
    });
</script>

尽管是并行下载,但是first-file.js中的代码肯定能在the-rest.js前面执行。

小结:

1、</body>闭合标签之前,将所有的<script>标签放在页面底部。能确保在脚本执行前页面已经完成了渲染

2、合并脚本,页面中的<script>标签越少,加载也就越快,响应也就越迅速。无论外链文件还是内嵌脚本都是如此。

3、有多种无阻塞下载JavaScript的方法

  使用<script>标签的defer属性

  使用动态创建的<script>元素来下载并执行代码

  使用XHR对象下载JavaScript代码并注入页面中

通过以上策略,可以极大的提高那些需要使用大量JavaScript的Web应用的实际性能

JS性能优化——加载和执行的更多相关文章

  1. 对于HTML页面中CSS, JS, HTML的加载与执行过程的简单分析

    来自   https://blog.csdn.net/u011088260/article/details/79563315   最近在研究HTML页面中JavaScript的执行顺序问题.在Java ...

  2. js&jquery页面加载完执行

    js <script type=”text/javascript”> window.onload=function (){ var userName=”xiaoming”; alert(u ...

  3. js dom元素加载完成执行

    //dom ready执行 function ready(fn){ if(document.addEventListener){ document.addEventListener('DOMConte ...

  4. JS脚本加载与执行对性能的影响

    高性能JavaScript-JS脚本加载与执行对性能的影响 在web产品优化准则中,很重要的一条是针对js脚本的加载和执行方式的优化.本篇文章简单描述一下其中的优化准则. 1. 脚本加载优化 1.1 ...

  5. 前端性能优化:细说JavaScript的加载与执行

    本文主要是从性能优化的角度来探讨JavaScript在加载与执行过程中的优化思路与实践方法,既是细说,文中在涉及原理性的地方,不免会多说几句,还望各位读者保持耐心,仔细理解,请相信,您的耐心付出一定会 ...

  6. 高性能JavaScript-JS脚本加载与执行对性能的影响

    在web产品优化准则中,很重要的一条是针对js脚本的加载和执行方式的优化.本篇文章简单描述一下其中的优化准则. 1. 脚本加载优化 1.1 脚本位置对性能的影响 优化页面加载性能的原则之一是将scri ...

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

    JavaScript 的性能优化:加载和执行 转自:https://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/ 随着 Web2.0 技术的 ...

  8. 性能优化-css,js的加载与执行

    前端性能优化 css,js的加载与执行 javascript是单线程的 一个网站在浏览器是如何进行渲染的呢? html页面加载渲染的过程 html渲染过程的一些特点 顺序执行,并发加载 词法分析 并发 ...

  9. 前端性能优化 css和js的加载与执行

    一个网站在浏览器端是如何进行渲染的? html本身首先会被渲染成 DOM 树,实际上 html 是最先通过网址请求过来的,请求过来之后,html 本身会由一个字节流转化成一个字符流,浏览器端拿的就是字 ...

随机推荐

  1. schema设计

    Schema设计   Schema:表的模式:   设计数据的表,索引,以及表和表的关系 在数据建模的基础上将关系模型转为数据库表 满足业务模型需要基础上根据数据库和应用特点优化表结构   关系模型图 ...

  2. 调整type="file"时的input的

    <input type="file"> 在ie下的视图如下 而在firefox下的是 一般为了界面美化的效果,会将其设置为透明,然后覆盖一个<a href = & ...

  3. 15 THINGS ALL GIRLS SHOULD KNOW ABOUT THEIR VAGINA

    Here are 15 facts that EVERY GIRL should know about her vagina. Don’t be shy! Your vagina is part of ...

  4. Python moni模拟鼠标事件

    7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 4 ...

  5. GIS可视化——麻点图

    一.引言 目前在客户端绘制POI(Point of Interest,兴趣点)的方式主要是div(Marker的形式).svg.canvas.VML(后边三种就是Vector Layer)几种方式,这 ...

  6. 修改Linux基本配置

    1.修改主机名 vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=server1.cn 2.修改ip地址 vi /etc/sysconfig/netw ...

  7. 2016.11.14 MIT challenge之课程总览

    Degree Chartshttp://catalog.mit.edu/degree-charts/computer-science-engineering-course-6-3/ MIT Chall ...

  8. 移植MonkeyRunner的图片对照和获取子图功能的实现-UiAutomator/Robotium篇

    依据前一篇文章<移植MonkeyRunner的图片对照和获取子图功能的实现-Appium篇>所述,由于Appium和MonkeyRunner有一个共同点--代码控制流程都是在client实 ...

  9. AutoCAD如何将dwf转成dwg格式

    dwf转成dwg怎么转, 悬赏分:30 - 解决时间:2009-11-22 10:19 重金:dwf转成dwg怎么转, 我是用在出图上的. 最佳答案 Design Web Format (DWF) 文 ...

  10. &lt;LeetCode OJ&gt; 189. Rotate Array

    189. Rotate Array Total Accepted: 55073 Total Submissions: 278176 Difficulty: Easy Rotate an array o ...