JavaScript 是如何工做的系列——第一篇
咱们都知道在默认状况下,JavaScript 的下载和执行会阻塞 HTML 的解析,结果会致使从打开页面到显示出网页内容的过程耗时较长,用户体验很差。本篇文章主要介绍了 JavaScript 的下载和执行是如何阻塞 HTML 解析的 ,以及如何避免阻塞。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)后,处理过程同上,后面依次类推。浏览器
因而可知,脚本的数量与消耗的时间是成正比的。在<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 属性后:
<!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>
使用 async 属性后:
<!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>
从上图中能够看到,JavaScript 脚本的执行顺序是:index1.js -> index3.js -> index2.js,这可能与你预想的执行顺序不一样。这是由于使用 async 属性的脚本,其执行顺序与文件大小、下载速度、解析速度等息息相关。
本文示例代码已上传到 github,感兴趣的读者能够自行下载。本地运行后,观察使用不一样的方式引入 JavaScript 脚本后,页面的加载速度。
本篇文章主要介绍了浏览器是什么时候开始下载和执行 JavaScript 的 ,以及阻塞 HTML 解析问题。下篇文章将深刻 JS 引擎,了解 JavaScript 代码执行的具体流程。敬请期待。
参考:
The Journey of JavaScript: from Downloading Scripts to Execution - Part I