心细的用户,可以从上面的http瀑布图比较看出:只有等到a.js加载完了,才开始加载b.js,然后再加载图片资源。我们称a.js阻塞b.js。这种现象,称之为js load block。
//filename:index.html <html> <head> <script type="text/javascript" src="a.js"></script> <script type="text/javascript" src="b.js"></script> </head> <body> <img src="http://static.perfgeeks.com/wp-content/uploads/2011/01/p_460_001.jpg" /> </body> </html>
有没有办法,让这三个不同的资源a.js, b.js, p_460_001.jpg同时加载,减少页面加载时间,避免因阻塞导致的减速影响。通常有以下几个办法
把所有javascript都内嵌在页面中- XHR Eval
- XHR Injection
- Iframe
- Script DOM Element
- Defer
- document.write
这里着重介绍最常用的XHR Injection和Script DOM Element二种方法
XHR Injection
XHR Injection和XHR Eval注入技巧都是通过XMLHttpRequest来获取Javascript脚本资源。然后,XHR Eval通过javascript函数eval执行脚本。而XHR Injection则是通过创建一个script的DOM元素,然后把XMLHttpRequest的响应注入script中。某些时候,eval会比较慢,所以我们不推荐使用XHR Eval技巧。
<html> <head> <script type="text/javascript"> function load_js(src) { var xml_http = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); xml_http.onreadystatechange = function() { if (xml_http.readyState == 4) { var script_element = document.createElement('script'); document.getElementsByTagName('head')[0].appendChild(script_element); script_element.text = xml_http.responseText; } } xml_http.open('GET', src, true); xml_http.send(''); } load_js('a.js'); load_js('b.js'); </script> </head> <body> <img src="http://static.perfgeeks.com/wp-content/uploads/2011/01/p_460_001.jpg" /> </body> </html><a href="https://pic.aikaiyuan.com/wp-content/uploads/2013/05/p_543_002.jpg"><img class="attachment-full" alt="p_543_002" src="https://pic.aikaiyuan.com/wp-content/uploads/2013/05/p_543_002.jpg" width="923" height="115" /></a>
上图可以看到,a.js, b.js和图片资源并行加载。但是XHR Injection有一个限制,不支持跨域加载。即获取的脚本必须部署在与页面相同的域中。同时,该技术不能保证脚本的执行顺序。
Script DOM Element
相较于XHR Injection而言,Script DOM Element技巧支持跨域加载,即可以加载来自不同域的text/javascript资源文件。这是因为该技术利用javascript动态创建script DOM元素并且设置src。
<html> <head> <script type="text/javascript"> function load_js(src) { var script_elem = document.createElement('script'); script_elem.type = 'text/javascript'; script_elem.src = src; document.getElementsByTagName('head')[0].appendChild(script_elem); } load_js('a.js'); load_js('b.js'); load_js('http://www.jt-tech.net/misc/jquery.js'); </script> </head> <body> <img src="http://static.perfgeeks.com/wp-content/uploads/2011/01/p_460_001.jpg" /> </body> </html><a href="https://pic.aikaiyuan.com/wp-content/uploads/2013/05/p_543_003.jpg"><img class="attachment-full" alt="p_543_003" src="https://pic.aikaiyuan.com/wp-content/uploads/2013/05/p_543_003.jpg" width="841" height="116" /></a>
上图也解决了javascript加载阻塞产生的减速影响,即a.js、b.js还有跨域jquery.js等并行加载。这种技巧也有一个小小缺陷,就是在某些浏览器(Firefox2.0/3.0/3.1、Safari3.2.1/4.0、Chrome1.0)会阻塞onload事件,影响用户体验
阻塞渲染、阻塞onload、执行顺序
阻塞渲染,当使用script src技术加载脚本时,浏览器停止渲染所有脚本后面的内容。这种阻塞给用户带来十分差劲的用户体验。应该尽量地避免这种情况出现。
//filename:cat bd_i.html
<html> <head> <script type="text/javascript" src="c.php"> </script> </head> <body> hello world </body> </html> //filename:vbd_i.html <html> <head> <script type="text/javascript"> function load_js(src) { var xml_http = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); xml_http.onreadystatechange = function() { if (xml_http.readyState == 4) { var script_element = document.createElement('script'); document.getElementsByTagName('head')[0].appendChild(script_element); script_element.text = xml_http.responseText; script_element.type = 'text/javascript'; } } xml_http.open('GET', src, true); xml_http.send(''); } load_js('c.php'); </script> </head> <body> hello world </body> </html>
//filename: c.php
<?php sleep(2); ?> function c() { return 2; }
二幅图对比,我们可以看到那条竖着的蓝线,表示脚本渲染完成。使用script src技术,则等到c.php(text/javascrip)加载完成之后完成的渲染。而使用XHR Injection技术加载脚本,并没有阻塞渲染。
阻塞onload,通常页面的onload要直到所有资源加载完成时才会被触发。如果加载一个较大的javascript文件,用户需要等待更长时间,浏览器状态栏才会显示“完成”,同时还有可能延迟默认输入框获取焦点。导致较差的用户体验。
执行顺序,当一个页面包含多个text/javascript脚本文件的时候。这些高级技术,使得这些脚本同时(并行)加载,受网络与文件大小的影响,脚本文件到到达顺序与开发人员期望的顺序有可能不一致。所以,使用这些高级技术的时候,尽量避免将相互调用的函数分散在不同的文件里面。
转载请注明:爱开源 » javascript脚本加载 js load block