JavaScript 从下载到执行(阻塞、defer、async)

JavaScript 是如何工做的系列——第一篇

前言

咱们都知道在默认状况下,JavaScript 的下载和执行会阻塞 HTML 的解析,结果会致使从打开页面到显示出网页内容的过程耗时较长,用户体验很差。本篇文章主要介绍了 JavaScript 的下载和执行是如何阻塞 HTML 解析的 ,以及如何避免阻塞。javascript

JavaScript 的下载和执行

咱们如下面这段代码为例:html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script src='./js/index1.js'></script>
    <script src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

index1.js 文件内容:java

console.log('index1');

index2.js 文件内容:git

console.log('index2');

index3.js 文件内容:github

console.log('index3);

当咱们在浏览器中打开上述 HTML 文件以后,浏览器就会开始解析 HTML 代码。当浏览器遇到 <head> 标签中的第一个 <script> 标签(index1.js)后,HTML 的解析会暂停。此时浏览器会发送一个 HTTP 请求去下载 index1.js 文件,当脚本下载完成,浏览器开始解析并解释执行下载的脚本( index1.js)。当 index1.js 执行完毕,浏览器继续解析 HTML 代码。当遇到第二个 <script> 标签(index2.js)后,处理过程同上,后面依次类推。浏览器

Image  6

因而可知,脚本的数量与消耗的时间是成正比的。在<head> 标签中引入的脚本越多,用户等待的时间越长。async

避免阻塞方式

那么有什么办法能够解决上述问题呢?ui

最多见的方式就是将 <script> 标签放到 HTML 文档最后,</body>标签以前。这会提升网页加载速度,由于 HTML 加载再也不受制于脚本加载,当 HTML 内容解析完毕后,才会开始加载脚本。spa

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
    <script src='./js/index1.js'></script>
    <script src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</body>
</html>

固然还有两种方式能够解决上述问题:(只适用于外部脚本)线程

  • defer 属性
  • async 属性(HTML5)

defer

使用 defer 属性后:

  • JavaScript 脚本下载在新的线程中进行,不会阻塞 HTML 解析;
  • 脚本下载完成后,不当即执行,在 HTML 解析完成后按照顺序执行。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script defer src='./js/index1.js'></script>
    <script defer src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

defer

async

使用 async 属性后:

  • JavaScript 脚本下载在新的线程中进行,不会阻塞 HTML 解析;(同 defer)
  • 脚本下载完成后,当即解析,此时会阻塞 HTML 的解析。解析完毕后,在另外一个线程中解释执行,此时不会阻塞 HTML 的解析。(多个脚本的执行顺序没法预测)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Demo</title>
    <script async src='./js/index1.js'></script>
    <script async src='./js/index2.js'></script>
    <script src='./js/index3.js'></script>
</head>
<body>
    <div>Downloading Scripts to Execution</div>
</body>
</html>

async

从上图中能够看到,JavaScript 脚本的执行顺序是:index1.js -> index3.js -> index2.js,这可能与你预想的执行顺序不一样。这是由于使用 async 属性的脚本,其执行顺序与文件大小、下载速度、解析速度等息息相关。

总结

comparison

本文示例代码已上传到 github,感兴趣的读者能够自行下载。本地运行后,观察使用不一样的方式引入 JavaScript 脚本后,页面的加载速度。

下一篇

本篇文章主要介绍了浏览器是什么时候开始下载和执行 JavaScript 的 ,以及阻塞 HTML 解析问题。下篇文章将深刻 JS 引擎,了解 JavaScript 代码执行的具体流程。敬请期待。

参考:

The Journey of JavaScript: from Downloading Scripts to Execution - Part I
相关文章
相关标签/搜索