script 标签 defer/async

218 阅读2分钟

    这两个属性都是用来处理脚本的行为,只适用于处理外部脚本文件,并告诉浏览器立即下载脚本。defer 告诉浏览器立即下载延迟执行,async 也会告诉浏览器立即下载;但标记 async 的脚本并不一定按顺序执行,第二个脚本可能会先于第一个脚本执行,因此确保两者互不依赖非常重要,指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。

博客文章

www.cnblogs.com/jiasm/p/768…

参考资料
developer.mozilla.org/zh-CN/docs/…

image

普通script

image

     一个普通的<script>标签的加载(浏览器内部优化可能异步)和解析都是同步的,会阻塞DOM的渲染,这也就是我们经常会把<script>写在<body>底部的原因之一,为了防止加载资源而导致的长时间的白屏,另一个原因是js可能会进行DOM操作,所以要在DOM全部渲染完后再执行。

defer(defer在IE<=9时支持但会有bug)

image

渲染完再执行

      加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本的执行需要等到文档所有元素解析完成之后,DOMContentLoaded事件触发执行之前。

async(async在IE<=9时不支持)

image

image

下载完就执行 

    async是乱序的,而defer是顺序执行,这也就决定了async比较适用于百度分析或者谷歌分析这类不依赖其他脚本的库。

     如果同时指定了两个属性,则会遵从async属性而忽略defer属性。

    规范情况下是,但是浏览器在实现的时候会做优化。

    《WebKit技术内幕》:

  1. 当用户输入网页URL的时候,WebKit调用其资源加载器加载该URL对应的网页。

  2. 加载器依赖网络模块建立连接,发送请求并接受答复。

  3. WebKit接收到各种网页或者资源的数据,其中某些资源可能是同步或异步获取的。

  4. 网页被交给HTML解释器转变成一系列的词语(Token)。

  5. 解释器根据词语构建节点(Node),形成DOM树。

  6. 如果节点是JavaScript代码的话,调用JavaScript引擎解释并执行。

  7. JavaScript代码可能会修改DOM树的结构。

  8. 如果节点需要依赖其他资源,例如图片、CSS、视频等,调用资源加载器来加载他们,但是他们是异步的,不会阻碍当前DOM树的继续创建;如果是JavaScript资源URL(没有标记异步方式),则需要停止当前DOM树的创建,直到JavaScript的资源加载并被JavaScript引擎执行后才继续DOM树的创建。