非阻塞JavaScript脚本加载【优化网站】
2014-03-14 10:33
585 查看
昨天在看《高性能JavaScript》,提到Javascript是以阻塞的方式加载的,也就是说:当JavaScript 运行时其他的事情不能被浏览器处理。根据Yahoo的建议,脚本放在最后。
让网页先显示,先得到一个正确的外观,再加载脚本,为网页添加各种功能,锦上添花,是一个很好的实践。以非阻塞的方式加载Javascript,就是这样的实践。其原理是使用一个脚本来加载其它脚本,这个脚本就是loader(或者其它你喜欢的名称)。loader最好放在最后,这样一个网页先显示出来,再通过loader加载其它功能脚本,如库、事件绑定等,可以提高网页的显示速度,提高网站的性能。
书中推荐使用YUI、LazyLoad、LABjs来加载脚本,但我更喜欢自己的定制的方式,因此也写了一个Loader。
这个Loader实现的功能有:
1. 可以加载 CSS 和 JS 文件,并且先加载CSS文件(如果有的话)。
2. JS文件有两种加载方式:同步与异步(默认)。这里所谓的同步,是指等待前一个JS文件加载完成后,再加载当前的JS文件,并且按loader.add的方法的调用顺序加载,执行的顺序与依赖关系有保障。如果一个JS文件被指定为异步加载,则它会在所有的同步文件加载完成后,再进行加载。所有异步加载的JS,不能保证它们能按顺序执行。
3. 如果是加载JS文件,支持加载完成后的回调函数,这个回调函数可以接收一个参数。
4. 通过add方法添加JS文件,addcss方法添加CSS文件,这时文件并未开始加载,最后通过load方法,才进行加载。如果文件在load方法之前已经通过add或addcss添加过,则不会重复加载。每次调用load方法后,清空add与addcss产生的缓存。
5. 实现我喜欢的 loader.add('file1.js').add('file2.js').add('file3.js', true).addcss('css1.css').add('css2.css').load(); 风格,
更详细的原理及其它的实现方式,用“非阻塞 javascript”来搜索一下园子里,就有好几篇文章,说得也很详细。
Loader代码如下
示例代码如下
让网页先显示,先得到一个正确的外观,再加载脚本,为网页添加各种功能,锦上添花,是一个很好的实践。以非阻塞的方式加载Javascript,就是这样的实践。其原理是使用一个脚本来加载其它脚本,这个脚本就是loader(或者其它你喜欢的名称)。loader最好放在最后,这样一个网页先显示出来,再通过loader加载其它功能脚本,如库、事件绑定等,可以提高网页的显示速度,提高网站的性能。
书中推荐使用YUI、LazyLoad、LABjs来加载脚本,但我更喜欢自己的定制的方式,因此也写了一个Loader。
这个Loader实现的功能有:
1. 可以加载 CSS 和 JS 文件,并且先加载CSS文件(如果有的话)。
2. JS文件有两种加载方式:同步与异步(默认)。这里所谓的同步,是指等待前一个JS文件加载完成后,再加载当前的JS文件,并且按loader.add的方法的调用顺序加载,执行的顺序与依赖关系有保障。如果一个JS文件被指定为异步加载,则它会在所有的同步文件加载完成后,再进行加载。所有异步加载的JS,不能保证它们能按顺序执行。
3. 如果是加载JS文件,支持加载完成后的回调函数,这个回调函数可以接收一个参数。
4. 通过add方法添加JS文件,addcss方法添加CSS文件,这时文件并未开始加载,最后通过load方法,才进行加载。如果文件在load方法之前已经通过add或addcss添加过,则不会重复加载。每次调用load方法后,清空add与addcss产生的缓存。
5. 实现我喜欢的 loader.add('file1.js').add('file2.js').add('file3.js', true).addcss('css1.css').add('css2.css').load(); 风格,
更详细的原理及其它的实现方式,用“非阻塞 javascript”来搜索一下园子里,就有好几篇文章,说得也很详细。
Loader代码如下
/** * 非阻塞JS文件加载, 对CSS文件也可以加载. * 文件加载顺序: * 1. 最先加载CSS文件, * 2. 然后加载所有同步的JS文件(并且按add方法添加的顺序), * 3. 最后加载所有非同步的JS文件(不一定按add方法添加的顺序). * 加载CSS文件方法: loader.addcss('path/to/file.css', 'screen print'); * 加载同步JS文件方法: loader.add('path/to/file.js', true[, callback[, callback_args]]); * 加载非同步JS文件方法: loader.add('path/to/file.js'[, false[, callback[, callback_args]]]); * 如果JS文件之间有依赖关系, 应当作为同步文件加载, 且按顺序调用add方法, 否则, 应以非同步文件加载 */ (function () { var loader = {}, _version = '0.0.1', syncjs = [], // 同步的JS asyncjs = [], // 非同步的JS css = [], // CSS // 加载CSS文件 _loadcss = function () { var head = document.getElementsByTagName('head')[0]; for (var i = 0, l = css.length; i < l; i++) { var c = document.createElement('link'); c.type = 'text/css'; c.rel = 'stylesheet'; c.href = css[i].src; c.media = css[i].media; head.appendChild(c); } css = []; }, // JS回调函数 // f 回调函数, 或包含回调函数的数组 // a 回调函数的参数 // o JS Element 对象 _onload = function (f, a, o) { if (o) { if (typeof f === 'function') { f = [f]; } if (o.readyState) { o.onreadystatechange = function () { if (o.readyState == 'loaded' || o.readyState == 'complete') { o.onreadystatechange = null; for (var i = 0, l = f.length; i < l; i++) { f[i](a); } } } } else { o.onload = function () { for (var i = 0, l = f.length; i < l; i++) { f[i](a); } } } } }, // o 用add方法增加的JS对象 // p JS Script标签的父元素 // f 回调函数 _loadjs = function (o, p, f) { var fs = [], js = document.createElement('script'); js.type = 'text/javascript'; if (typeof o.callback === 'function') { fs.push(o.callback); } if (typeof f === 'function') { fs.push(f); } if (fs.length > 0) { _onload(fs, o.args, js); } js.src = o.src; p.appendChild(js); }, // 加载同步的JS文件 _loadsyndjs = function () { if (syncjs.length > 0) { var head = document.getElementsByTagName('head')[0], js = syncjs.shift(); _loadjs(js, head, _loadsyndjs); } else { _loadasyncjs(); } }, // 加载非同步的JS文件 _loadasyncjs = function () { var head = document.getElementsByTagName('head')[0]; for (var i = 0, l = asyncjs.length; i < l; i++) { _loadjs(asyncjs[i], head); } asyncjs = []; }; /** * JS或CSS文件是否已经包含了 */ syncjs.has = asyncjs.has = css.has = function (v) { for (var i = 0, l = this.length; i < l; i++) { if (v == this[i].src) return true; } return false; } /** * 加载JS * @param u JS路径 * @param sync 是否同步 * @param callback 加载完成后的回调函数 * @param args 回调函数的参数 */ loader.add = function (u, sync, callback, args) { var js = sync ? syncjs : asyncjs; if (!js.has(u)) { js.push({'src': u, 'callback': callback, 'args': args}); } return this; }; /** * 加载CSS * @param u CSS路径 * @param media CSS毁林类型 */ loader.addcss = function (u, media) { if (!css.has(u)) { css.push({'src': u, 'media': media || 'screen'}); } return this; }; /** * 开始加载 */ loader.load = function () { _loadcss(); _loadsyndjs(); }; /** * 版本 */ loader.version = function () { return _version; }; window.loader = loader; })(window);
示例代码如下
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>非阻塞脚本加载测试</title> </head> <body> <div>TODO write content</div> <script type="text/javascript" src="../loader.js"></script> <script type="text/javascript"> loader.add('test.js').add('../vendor/jquery-1.4.1.js', true, function (s) { $('body').append('<p>jQuery loaded</p><p>' + s + '</p>'); }, 'param').add('test.js').add('test2.js', true, function() { $('body').append('<p>' + loader.version() + '</p>'); }).addcss('http://www.cnblogs.com/css/reset.css').load(); </script> </body> </html>
相关文章推荐
- 高性能网站优化-无阻塞加载脚本
- 高性能Javascript--脚本的无阻塞加载策略
- 高性能Javascript--脚本的无阻塞加载策略
- JavaScript中的无阻塞加载性能优化方案
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
- 前端优化之无阻塞加载脚本
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
- JavaScript中的无阻塞加载性能优化方案
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
- 高性能Javascript:脚本的无阻塞加载策略
- javascript脚本阻塞与模块化加载
- javascript脚本阻塞与模块化加载
- 高性能JavaScript:脚本的无阻塞加载策略
- javascript 无阻塞脚本 ,通过dom动态加载
- 无阻塞加载javascript脚本
- JavaScript无阻塞加载性能优化方案
- 高性能Javascript--脚本的无阻塞加载策略
- 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密
- 高性能Javascript--脚本的无阻塞加载策略
- 高性能Javascript--脚本的无阻塞加载策略