javascript 文件的同步加载与异步加载实现原理


Posted in Javascript onDecember 13, 2012

HTML 4.01 的script属性
charset: 可选。指定src引入代码的字符集,大多数浏览器忽略该值。
defer: boolean, 可选。延迟脚本执行,相当于将script标签放入页面body标签的底部,js脚本会在document的DOMContentLoaded之前执行。除IE和较新版本的Firefox外,其他浏览器并未支持。
language: 已废弃。大部分浏览器会忽略该值。
src: 可选。指定引入的外部代码文件,不限制后缀名。
type: 必选。指定脚本的内容类型(MIME类型)。现实中通常不指定该值也可以,浏览器会默认当作text/javascript类型来解释执行。

HTML5中的script属性
script 标签在HTML5中除了具备HTML5新标准定义的属性以外,和HTML4.01相比移除了language属性,修改了type属性为可选的(默认text/javascript),并新增了一个属性async。
async :boolean, 属性的作用,定义脚本是否异步执行,取值true或false。
如果 async 设为 true ,会忽略 defer 属性。
异步执行的 js 文件被假定为不使用 document.write() 向加载中的 document 写入内容,因此不要在 异步执行的 js 文件的加载执行过程中使用 document.write()
除了 script 标签属性外,页面引入 js 文件的方式影响其加载执行方式:
任何以添加 script 节点(例如 appendChild(scriptNode) ) 的方式引入的js文件都是异步执行的 (scriptNode 需要插入document中,只创建节点和设置 src 是不会加载 js 文件的,这跟 img 的预加载不能类比 )
html文件中的<script>标签中的代码或src引用的js文件中的代码是同步加载和执行的
html文件中的<script>标签中的代码使用document.write()方式引入的js文件是异步执行的
html文件中的<script>标签src属性所引用的js文件的代码内再使用document.write()方式引入的js文件是同步执行的
使用 Image 对象异步预加载 js 文件(不会被执行)

不要使用类似下面这种做法,这样并不会发起加载 js 文件的请求:
divNode.innerHTML = '<script src="xxx.js"></script>';
window.onload 事件会在 js 文件加载完毕才触发(即使是异步加载)
=====================================================
1、
<script>
//同步加载执行的代码
</script>
2、
<script src="xx.js"></script> //同步加载执行xx.js中的代码
3、
<script>
document.write('<script src="xx.js"><\/script>'); //异步加载执行xx.js中的代码
</script>
4、
<script src="xx.js"></script>
xx.js中有下面代码:

document.write('<script src="11.js"><\/script>'); 
document.write('<script src="22.js"><\/script>');

则xx.js和11.js、22.js 都是同步加载和执行的。
如果 xx.js 、11.js 和 22.js 以插入 script 节点方式异步加载,则 11.js 和 22.js 是异步加载的,
如果 xx.js 以script 节点方式异步加载, 11.js 和 22.js 以 document.write(script) 方式加载,则 11.js 和 22.js 是同步加载的(经最新的浏览器测试, 在chrome 下,xx.j 异步加载执行已经无法使用 document.write() 向文档写入内容的 ,但是 firefox 和IE 却可以在 document 关闭之前写入(方法是在 html 中alert阻止文档关闭))
测试:在11.js中 alert()(不要用 for 循环,浏览器是单线程执行的,持续执行任何一段代码都会导致其余代码被阻塞) , 22.js 中 console.log() ,可以看到 22.js中的代码被阻塞
5、
下面这种方式,xx.js会在appendChild执行之后异步加载执行
var script = document.createElement("script"); 
script.setAttribute("src","xx.js"); 
documenrt.getElementsByTagName("head")[0].appendChild(script);

6、使用 Image 对象异步预加载 js 文件(不会被执行)
Image 的 src 被赋值时即发起请求,而且对文件类型不挑剔(图片也可能是有脚本动态创建的,比如验证码),因此可以将 js 文件的 url 赋给 image.src, js 加载之后被浏览器缓存.
var img = new Image(); 
img.onload = function(){ alert(1); } ; //由于返回的js文件 MIME 不是图片,onload回调函数并不会被触发 
img.src = 'http://localhost/test/loadjs/try.2.js'; 
var s = document.createElement("script"); 
var h = document.getElementsByTagName("head")[0]; 
//执行 js 
s.src=img.src; 
h.appendChild(s);

一个加载 js 文件的 函数:
var loadJS = function(url,callback){ 
var head = document.getElementsByTagName('head'); 
if(head&&head.length){ 
head = head[0]; 
}else{ 
head = document.body; 
} 
var script = document.createElement('script'); 
script.src = url; 
script.type = "text/javascript"; 
head.appendChild( script); 
script.onload = script.onreadystatechange = function(){ 
//script 标签,IE 下有 onreadystatechange 事件, w3c 标准有 onload 事件 
//这些 readyState 是针对IE8及以下的,W3C 标准的 script 标签没有 onreadystatechange 和 this.readyState , 
//文件加载不成功 onload 不会执行, 
//(!this.readyState) 是针对 W3C标准的, IE 9 也支持 W3C标准的 onload 
if ((!this.readyState) || this.readyState == "complete" || this.readyState == "loaded" ){ 
callback(); 
} 
}//end onreadystatechange 
}

对于第4点的测试(同步加载)(其中插入 alert 很容易看到加载时的阻塞)
tryjs.html
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<script src="tryjs.js" 
onload="if(!document.all){console.log('outer js callback, not IE');}" 
onreadystatechange="console.log('outer js callback ',this.readyState,' IE');"></script> 
<body> 
</body> 
</html>

tryjs.js
console.log('write begin'); 
document.write('<script src="try.1.js" onreadystatechange="console.log(\'file 1 callback \',this.readyState,\' IE\');" onload="if(!document.all){console.log(\'file 1 callback,NOT IE \');}"><\/script>'); 
document.write('<script src="try.2.js" onreadystatechange="console.log(\'file 2 callback \',this.readyState,\' IE\');" onload="if(!document.all){console.log(\'file 2 callback,NOT IE \');}"><\/script>'); 
console.log('write finished');

try.1.js
console.log('loadjs 1 begin'); 
console.log('loadjs 1 finished');

try.2.js
console.log('loadjs 2 begin'); 
console.log('loadjs 2 finished');

测试结果(file 2 和 file 1 的 callback complete 在IE7\8\9次序不确定)
IE 7:
日志: outer js callback loading IE
日志: outer js callback loaded IE
日志: write begin
日志: write finished
日志: outer js callback complete IE
日志: file 1 callback loading IE
日志: file 2 callback loading IE
日志: loadjs 1 begin
日志: loadjs 1 finished
日志: loadjs 2 begin
日志: loadjs 2 finished
日志: file 2 callback complete IE
日志: file 1 callback complete IE

IE8:
日志: outer js callback loading IE
日志: outer js callback loaded IE
日志: write begin
日志: write finished
日志: outer js callback complete IE
日志: file 1 callback loading IE
日志: file 2 callback loading IE
日志: loadjs 1 begin
日志: loadjs 1 finished
日志: loadjs 2 begin
日志: loadjs 2 finished
日志: file 2 callback complete IE
日志: file 1 callback complete IE

IE9:
日志: write begin
日志: write finished
日志: outer js callback complete IE
日志: file 1 callback loading IE
日志: file 2 callback loading IE
日志: loadjs 1 begin
日志: loadjs 1 finished
日志: loadjs 2 begin
日志: loadjs 2 finished
日志: file 1 callback complete IE
日志: file 2 callback complete IE

FIREFOX:
write begin
write finished
outer js callback, not IE
loadjs 1 begin
loadjs 1 finished
file 1 callback,NOT IE
loadjs 2 begin
loadjs 2 finished
file 2 callback,NOT IE

CHROME:
write begin
write finished
outer js callback, not IE
loadjs 1 begin
loadjs 1 finished
file 1 callback,NOT IE
loadjs 2 begin
loadjs 2 finished
file 2 callback,NOT IE

Javascript 相关文章推荐
jQuery 使用手册(五)
Sep 23 Javascript
jQuery拖动图片删除示例
May 10 Javascript
动态获取复选框checkbox选中个数的jquery代码
Jun 25 Javascript
javascript判断机器是否联网的2种方法
Aug 09 Javascript
jQuery CSS3相结合实现时钟插件
Jan 08 Javascript
jquery PrintArea 实现票据的套打功能(代码)
Mar 17 Javascript
vue使用Axios做ajax请求详解
Jun 07 Javascript
angular2+node.js express打包部署的实战
Jul 27 Javascript
详解jQuery-each()方法
Mar 13 jQuery
详解React 元素渲染
Jul 07 Javascript
原生js滑动轮播封装
Jul 31 Javascript
JS画布动态实现黑客帝国背景效果
Nov 08 Javascript
javaScript复制功能调用实现方案
Dec 13 #Javascript
js遍历td tr等html元素
Dec 13 #Javascript
js关闭模态窗口刷新父页面或跳转页面
Dec 13 #Javascript
HTML复选框和单选框 checkbox和radio事件介绍
Dec 12 #Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
Dec 12 #Javascript
用javascript模仿ie的自动完成类似自动完成功的表单
Dec 12 #Javascript
javascript实现图片切换的幻灯片效果源代码
Dec 12 #Javascript
You might like
PHP设置头信息及取得返回头信息的方法
2016/01/25 PHP
Yii2框架实现数据库常用操作总结
2017/02/08 PHP
PHP实现新型冠状病毒疫情实时图的实例
2020/02/04 PHP
Js的MessageBox
2006/12/03 Javascript
iframe 自适应高度[在IE6 IE7 FF下测试通过]
2009/04/13 Javascript
JS+XML 省份和城市之间的联动实现代码
2009/10/14 Javascript
正则表达式搭配js轻松处理json文本方便而老古
2013/02/17 Javascript
ajax请求get与post的区别总结
2013/11/04 Javascript
JavaScript中的boolean布尔值使用学习及相关技巧讲解
2016/05/26 Javascript
浅析JavaScript动画模拟拖拽原理
2016/12/09 Javascript
js使用Replace结合正则替换重复出现的字符串功能示例
2016/12/27 Javascript
详解微信小程序Page中data数据操作和函数调用
2017/09/27 Javascript
layui中layer前端组件实现图片显示功能的方法分析
2017/10/13 Javascript
浅谈es6语法 (Proxy和Reflect的对比)
2017/10/24 Javascript
JavaScript 浏览器对象模型BOM原理与常见用法实例分析
2019/12/16 Javascript
使用vue实现HTML页面生成图片的方法
2020/03/12 Javascript
微信小程序开发之获取用户手机号码(php接口解密)
2020/05/17 Javascript
js禁止查看源文件屏蔽Ctrl+u/s、F12、右键等兼容IE火狐chrome
2020/10/01 Javascript
如何利用 JS 脚本实现网页全自动秒杀抢购功能
2020/10/12 Javascript
js实现类选择器和name属性选择器的示例步骤
2021/02/07 Javascript
python实现dict版图遍历示例
2014/02/19 Python
python开发之文件操作用法实例
2015/11/13 Python
Python爬虫辅助利器PyQuery模块的安装使用攻略
2016/04/24 Python
python获取代理IP的实例分享
2018/05/07 Python
使用PyTorch将文件夹下的图片分为训练集和验证集实例
2020/01/08 Python
对tensorflow 中tile函数的使用详解
2020/02/07 Python
python实现提取COCO,VOC数据集中特定的类
2020/03/10 Python
如何理解Python中包的引入
2020/05/29 Python
网络安全类面试题
2015/08/01 面试题
职称评定自我鉴定
2014/03/18 职场文书
毕业实习证明范本
2015/06/16 职场文书
重阳节活动主持词
2015/07/04 职场文书
幼儿园开学温馨提示
2015/07/15 职场文书
无故旷工检讨书
2015/08/15 职场文书
2019年干货:自我鉴定
2019/03/25 职场文书
Python Pandas解析读写 CSV 文件
2022/04/11 Python