html解析和渲染过程 与 Script标签和脚本执行顺序
几个首要特性:
- 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>