html解析和渲染过程 与 Script标签和脚本执行顺序

时间:2023-01-26 14:54:39

 

几个首要特性:

  • script标签(不带deferasync属性)的会阻止文档渲染。相关脚本会立即下载并执行。
  • document.currentScript可以获得当前正在运行的脚本(Chrome 29+, FF4+)
  • 脚本顺序再默认情况下和script标签出现的顺序一致

 

deferasync属性(deferasync没有完全兼容所有浏览器

  • 仅有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>