几个首要特性:
- script标签(不带
defer
或async
属性)的会阻止文档渲染。相关脚本会立即下载并执行。 -
document.currentScript
可以获得当前正在运行的脚本(Chrome 29+, FF4+) - 脚本顺序再默认情况下和script标签出现的顺序一致
有defer
或async
属性(defer和
async没有完全兼容所有浏览器
)
- 仅有async属性,脚本会异步执行
- 仅有defer属性,脚本会在文档解析完毕后执行
- 两个属性都没有,脚本会被同步下载并执行(顺序下载,顺序执行),期间会阻塞文档解析
如下示例A1,A2,A3
<!-- HTML code -->
<script src="https://snipt.net/raw/A1_7b08744009c450e07c0bfc1d606fc72e/"></script>
<script src="https://snipt.net/raw/A2_a2e8c05c1f6fc0e47d259aa899304e89/"></script>
<script src="https://snipt.net/raw/A3_4fab3017d3d46cbfc4bbd88aab006650/"></script>
当第二个文件A2的尺寸远大于另外两个文件,A1下载执行不受影响,A3在A2下载执行完成之后下载
另外,当<script>标签下载执行过程中,document.ready事件等待所有<script>内容下载完成后才能被触发;
优化方案
一:异步加载脚本
setTimeout(function(){
var s = document.createElement('script');
s.src = "/will-not-stop-loading.js";
document.body.appendChild(s);
});
setTimeout
未指定第二个参数(延迟时间),会立即执行第一个参数传入的函数。 但是JavaScript引擎会将该函数插入到执行队列的末尾。 这意味着正在进行的DOM渲染过程完全结束后(此时浏览器忙提示当然会消失),才会调用上述函数
二:load事件(推荐)
$(window).load(function(){
$('script[type="text/async-script"]').each(function(idx, el){
var $script = $('<script>');
if(el.dataset.src) $script.attr('src', el.dataset.src);
else $script.html(el.text);
$script.appendTo('body');
el.remove();
});
});
- 对于外部
<script>
,生成一个新的包含正确src
的<script>
。 - 对于行内
<script>
,生成一个新的包含正确内容的<script>
,type
默认即为"application/javascript"
。
该方法采用DOM中<script>
加载的方式,没有AJAX+Eval改变脚本中当前路径的缺点。 http://harttleland.com中的Google Analytics、MathJax等脚本都采用这种处理方式
另外一种写法
<script type="text/javascript">
// 加载较慢会阻塞页面渲染的脚本
function loadComplete(){
var hm1 = document.createElement("script");
hm1.src = "./secondLoad.js";
var hm2 = document.createElement("script");
hm2.src = "./thirdLoad.js";
document.body.appendChild(hm1)
hm1.onload = function(){
document.body.appendChild(hm2)
}
}
</script>
<!-- 加载最快且优先级最高的脚本 -->
<script type=text/javascript onload='loadComplete()' src='./firstAndFastLoad.js'></script>
三:document.write()会把输出写入到脚本文档所在的位置,浏览器解析完documemt.write()所在文档内容后,继续解析document.write()输出的内容,
然后在继续解析HTML文档
<script type="text/javascript">//<![CDATA[
document.write('<script type="text/javascript" src="test.js"><//script>');
document.write('<script type="text/javascript">');
document.write('alert(2);')
document.write('alert("我是" + tmpStr);');
document.write('<//script>'); //]]>
</script>