script 标签中的async和defer

默认 script 标签会阻塞 HTML 渲染页面,要等【下载并执行完】才会接着渲染。async 下载 js 不会阻塞 HTML 渲染页面,在 js 下载完后运行, 因为是单线程运行时会阻塞页面渲染。defer 同样是异步下载 js ,不过在页面渲染完后才执行,执行优先级低于没有 defer 的 js 文件。

async vs defer
async 是异步的意思,不阻塞解析 HTML构建DOM 树,defer 是推迟的意思,同样不阻塞解析HTML 构建DOM 树,并在解析完HTML 后延时执行。

我们看一下Dev Tools 下的 Performance 标签下不同属性下的执行顺序。

Async 不阻塞HTML 解析完成,HTML 解析完成会触发DOMContentLoaded 事件。
Async 和 defer 都不阻塞 First Paint,不会因为请求脚本超时而页面一直不显示出来。
  1. First Paint(首次绘制):指浏览器首次将像素渲染到屏幕上的时间点,这时用户可以看到一个有颜色的屏幕。
  2. First Contentful Paint(首次内容绘制):指页面中首次绘制文本、图像、SVG、canvas 元素等非空内容的时间点,这时用户可以看到第一批有意义的内容,如文本、图像等,是一个更准确反映用户首次感受到页面加载速度的指标。
  3. Largest Contentful Paint(最大内容绘制):指页面中最大的可见区域内的内容被绘制的时间点,通常是图片、视频等大型媒体元素。该指标可以帮助开发者确定在页面加载期间最影响用户体验的元素,并优化这些元素的加载方式,以提高页面加载速度和用户体验。

这些事件发生在浏览器的 LayoutPaint 阶段之后,但在用户可以看到页面内容之前。

commit 是将之前的 Layout、Paint 的结果绘制到页面上,即生成一个由多个图层(Layer)组成的位图(Bitmap),该阶段还会生成一个 DisplayList,并将其提交给浏览器进程的渲染器线程(Renderer Thread)。

动态加载 script 默认是异步

动态加载 script 默认是异步的,如果需要动态下载的这几个 js 文件按照顺序执行,避免依赖上造成的问题,需要设置 async 为 false,否则后下载完的大尺寸 js 文件 bigSizeScript.js 会比先下载完成的小 js 文件 smallSizeScript.js 后执行。

function addScript(src){
    var script = document.createElement('script')
    script.setAttribute('type','text/javascript')
    script.src = src
    script.async = false
    document.body.appendChild(script)
}
addScript('bigSizeScript.js')
addScript('smallSizeScript.js')

Leave a Reply

Your email address will not be published. Required fields are marked *