动态脚本元素实现js的异步加载和执行
动态脚本元素实现JS的异步加载和执行即指——通过动态创建添加script标签实现外部js的异步加载与执行
该方式的特点
‘script.src = “file1.js”’一旦执行完毕,则马上开始异步加载(下载)外部js文件
文件的下载与运行都不会阻塞页面,即js的下载与运行都是异步的
外部js文件一旦加载完成则立即执行
使用外部js中的代码的时机
请看下面的例子:
/*外部js文件——demo.js*/
function test(){
console.log(100);
}
/*引用外部js的本地文件*/
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'demo.js';
document.head.appendChild(script);
test();//在此使用外部js中的代码
然而你会发现,会报错——test未定义
在对上面代码进行改进
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'demo.js';
document.head.appendChild(script);
setTimeout(function(){
test();//100
}, 2000);
这是为什么?
因为‘script.src = ‘demo.js’’执行完毕后,马上异步加载外部js文件,然后后续代码继续正常运行,当运行到‘test()’时,可能外部js文件还未加载完毕(比如在网络不好的情况下…),自然出现test未定义。而延时的目的就是让外部在加载完毕的情况下才使用其中的代码
然而使用定时器来解决这个问题显然是滑稽的,看下面的封装方法
对动态脚本元素的兼容封装
function loadScript(url, callback){
var script = document.createElement ("script");
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
}
}else { //Others
script.onload = function(){
callback();
}
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
代码解析:
- if (script.readyState == “loaded” || script.readyState == “complete”)的依据
IE中的,script元素有一个readyState属性,它的值伴随着下载外部js文件的过程而改变。共有五种取值,如下:
1.uninitialized——初始状态
2.loading——下载开始
3.loaded——下载完成
4.interactive——下载完成但尚不可用
5.complete——所有数据已经准备好
但是readyState的这些取值不一定全部出现。在实际中,我们只需要关注loaded与complete。但是,有时script元素会得到loaded却从不出现complete;有时得到complete,却不出现loaded;有时又有可能全部出现
因此我们需要对上述两种情况做判断
- script.onreadystatechange = null的依据
前面说到,有时loaded与complete可能全部出现。将事件置为null,解除事件,以免触发两次
一定要先绑定事件,再执行script.src = url,以免出现‘使用外部js中的代码的时机’中所述的问题
该方式不保证文件的加载执行顺序