正常情况下,脚本元素会阻止下载页面内容,直到这个脚本文件下载解析并执行完毕。
无阻塞地下载
可以通过一些模式来防范阻塞下载的问题:
使用XHR请求载入脚本,并使用eval()将其转换为字符串。
但是这种方法受到XHR同域限制,并且使用了eval()这种不好的模式、使用defer和async属性,但并不能在所有浏览器上都生效
http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html- 使用动态的script元素
最后一种方法是一个比较好的。可实现的模式。
这种方式需要创建一个新的脚本元素、设置其src属性,最后将该元素添加到网页文件中。
var script = document.createElement("script");
script.src = "all.js";
document.documentElement.firstChild.appendChild(script);//添加到head标签中
这种模式的缺点是如果其他脚本文件依赖于all.js,由于此脚本是异步载入的,因此无法保证此脚本什么时候能够载入完毕。
延迟加载
在页面载入完成之后载入外部文件的技术称为延迟加载。
通常将一大段代码切为两部分是十分有益的:
- 一部分代码用于初始化页面并将事件处理程序添加到UI元素上
- 第二部分代码只在用户交互或者其他条件下才能用上
这样做的目的是可以渐进式地载入页面,尽可能快地提供目前需要使用的信息,而其余的内容可以在用户浏览该页面时在后台载入。
载入第二部分代码的方法非常简单,只需要再一次为head或者body添加动态脚本:
window.onload = function(){
var script = document.createElement("script");
script.src = "lazy.js";
document.documentElement.firstChild.appendChild(script);
}
按需加载
在延迟加载模式之外,如果想要在需要的时候再载入脚本的话,就是按需加载。
可以创建一个require方法,该方法包含需要加载的脚本的名称和当附加脚本加载完成后需要执行的回调函数。
require("extra.js",function(){
//……
})
如何实现require:
function require(file,callback){
var script = document.getElementsByTagName("script")[0];
var newjs = document.createElement("script");
newjs.onload = function(){
callback();
};
newjs.src = file;
script.parentNode.insertBefore(newjs,script);
}
预加载js
在延迟加载和按需加载模式中,我们延迟加载当前页面所需的脚本。此外,还可以预加载当前页面不需要、但是在后续页面中可能需要的脚本。当用户打开街下载的网页后,所需要的脚本已经预先加载了,进而用户感觉会快了许多。
预加载可以使用动态脚本模式来实现,但是这意味着该脚本将被解析和执行。而解析会增加预加载的时间,执行脚本则可能会导致js错误,因为这些脚本是要在第二个页面执行的,可能会寻找某个当前页面不存在的DOM元素。
这时我们要考虑加载脚本而不解析和执行脚本。
首先,可以利用图像ping模式来发出请求:
new Image().src = "preload.js";
也可以使用一个<object>
元素来代替脚本元素,并将其data属性指向脚本的URL:
var obj = document.createElement("object");
obj.data = "preload.js";
document.body.appendChild(obj);
为了避免显示出该对象,应该将该对象的width和height属性都设置为0。