Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async和defer对script脚本加载的影响 #10

Open
BigKongfuPanda opened this issue Apr 11, 2019 · 0 comments
Open

async和defer对script脚本加载的影响 #10

BigKongfuPanda opened this issue Apr 11, 2019 · 0 comments

Comments

@BigKongfuPanda
Copy link
Owner

BigKongfuPanda commented Apr 11, 2019

直接使用script脚本的话,html会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM渲染。
这是因为 UI 渲染线程与 JS 引擎是互斥的,当 JS 引擎执行时 UI 线程会被挂起。

defer

如果script标签设置了该属性,则浏览器会异步的下载该文件并且不会影响到后续 DOM 的渲染;
如果有多个设置了 defer 的script标签存在,则会按照顺序执行所有的script;
defer 脚本会在文档渲染完毕后, DOMContentLoaded 事件调用前执行。

async

async 的设置,会使得script脚本异步的加载并在允许的情况下执行。
async 的执行,并不会按着script在页面中的顺序来执行,而是谁先加载完谁执行。
DOMContentLoaded 事件的调用不会管带有 async 属性的script脚本是否加载完和执行完

注意点

带有 asyncdefer 的脚本的下载是和 HTML 的下载与解析是并行的,但是 JS 的执行一定是和 UI 线程是互斥的,像下面这张图所示,async 在下载完毕后的执行会阻塞HTML的解析

image
他们有两处不同:

项目 async defer
顺序 带有 async 的脚本是优先执行先加载完的脚本,他们在页面中的顺序并不影响执行的顺序 带有 defer 的脚本按照他们在页面中出现的顺序依次执行
DOMContentLoaded 带有 async 的脚本也许会在页面没有完全下载完之前就加载,这种情况会在脚本很小或本地缓存,并且页面很大的情况下发生 带有 defer 的脚本会在页面加载和解析完毕后执行,刚好在 DOMContentLoaded 之前执行

defer 是会阻塞 DOMContentLoaded 的,被 defer 的脚本要在 DOMContentLoaded 触发前执行,所以如果HTML很快就加载完了(先不考虑 CSS 阻塞 DOMContentLoaded 的情况),而 defer 的脚本还没有加载完,浏览器就会等,等到脚本加载完,执行完,再触发 DOMContentLoaded

外部样式表并不会阻塞 DOM 的解析,所以 DOMContentLoaded 并不会被它们影响。不过仍然有一个陷阱:如果在样式后面有一个内联脚本,那么脚本必须等待样式先加载完。

简单来说,JS 因为有可能会去获取 DOM 的样式,所以 JS 会等待样式表加载完毕,而 JS 是阻塞 DOM 的解析的,所以在有外部样式表的时候,JS 会一直阻塞到外部样式表下载完毕

<link type="text/css" rel="stylesheet" href="style.css">
<script>
  // 脚本直到样式表加载完毕后才会执行。
  alert(getComputedStyle(document.body).marginTop);
</script>

发生这种事的原因是脚本也许会像上面的例子中所示,去得到一些元素的坐标或者基于样式的属性。所以他们自然要等到样式加载完毕才可以执行。

DOMContentLoaded 需要等待脚本的执行,脚本又需要等待样式的加载。

HTML 页面的生命周期

HTML页面的生命周期有以下三个重要事件:

  • DOMContentLoaded:浏览器已经完全加载了 HTML,DOM 树已经构建完毕,但是像 <img> 和样式表等外部资源可能并没有下载完毕;
  • load:浏览器已经加载了所有的资源(图片,样式表等);
  • beforeunload/unload:当用户离开页面的时候触发

每个时间都有特定的用途:

  • DOMContentLoaded:DOM 加载完毕,所以 JS 可以访问所有的 DOM 节点,初始化界面;
  • load:附加资源已经加载完毕,可以在此事件触发时获得图像的大小(如果没有被在 HTML/CSS 中指定);
  • beforeunload/unload:用户正在离开页面,可以询问用户是否保存了更改以及是否确定要离开页面。

参考资料

[译]页面生命周期:DOMContentLoaded, load, beforeunload, unload解析
css加载会造成阻塞吗?
浅谈script标签中的async和defer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant