JS面试题---script标签中的async(异步)和defer(推迟)的区别

99 阅读3分钟

前言

在script标签中不使用async和defer属性加载外部脚本时,浏览器会立即加载并执行相应的外部脚本。这样就阻塞了后续文档的加载。

所以,我们经常会把script写在body底部,原因包括以下两个

  1. 普通的script标签的加载和解析都是同步的,会阻塞DOM的渲染。为了防止加载资源而导致的长时间的白屏,
  2. js可能会进行DOM操作,所以要在DOM全部渲染完后再执行。

一、概念

  • async

属性可选,表示应该立即开始下载脚本,但不能阻止其他页面动作,比如下载资源或等待其他脚本加载。只对外部脚本有效。


在渲染页面元素的同时下载外部脚本资源,不会阻塞页面的加载,但下载完后会立即执行脚本内容。

  • defer

属性可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。在IE7及更早的版本中,对行内脚本也可以指定这个属性。

使用defer属性后,脚本会被延迟到整个页面都解析完毕后再运行。相当于告诉浏览器立即下载外部文件,但是延迟执行


外部脚本就是通过src属性引入的其它脚本文件,浏览器会对外部脚本文件进行缓存,提高页面加载速度。 行内脚本就是在script标签内书写的js代码

二、区别

1. 页面渲染的同步和异步

在这里插入图片描述 蓝色代表js脚本网络加载时间,红色代表 js 脚本执行时间,绿色代表 html 解析。

  • 普通的script标签的加载和解析都是同步的,会阻塞DOM的渲染。
  • defer属性的会在html解析的同时异步下载网络资源,直到html解析结束,才会执行,若资源在html解析完成后仍未下载完成,那么defer脚本继续加载,加载完成后直接执行
  • async属性的会在html解析的同时异步下载网络资源,但下载完后会立即执行,可能会阻塞DOM的渲染

2. 与页面加载事件的关系

  • load

当页面的html、css、js、图片等资源都已经加载完之后才会触发 load 事件

  • DOMContentLoaded

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。


区别:

  • “async可能会在 DOMContentLoaded之前或之后,保证在页面的 load 事件之前执行。”
  • ”defer保证在触发DOMContentLoaded之前执行,执行完毕后触发DOMContentLoaded事件。“

3. 多个script标签下的执行顺序

  • 普通的script标签,HTML5 规范要求脚本应该按照它们出现的顺序执行。
  • 对于async属性的script标签,执行的顺序不确定,先下载完的脚本先执行
  • 对于defer属性的script标签,脚本执行的顺序与下载的完成时间无关,按照script标签位置顺序执行

三、使用场景

  • async

主要是不涉及操作DOM的事件

  • defer

操作DOM的脚本,为防止元素尚未加载完成,脚本找不到元素报错。