水果摊小老板,学习 JS 运行机制

说说 JS 运行机制?

假如我是路边卖水果摊的小老板,遇到这个问题了,想尽快寻找答案。
靠!小老板啥都不知道,只看懂了前面 “说说” 两个字,还能怎么办?百度吧

1. 先查一下什么是 JS。

百度结果,小老板懂了,哦!JS 是一种脚本语言。ECMA国际组织为它制定了统一的 ECMAScrip 标准。现在主要被用于浏览器的web开发,以及服务器编程(Node.js)

  • 浏览器的JS:JS = ECMAScript + DOM + BOM
  • 服务器Node.js:JS = ECMAScript + os + file + net + database

2. 小老板重新定义了问题:“说说浏览器中 JS 的运行机制?”

小老板想了想:“靠!浏览器的本身怎么运行我都不知道,更别说浏览器里的 JS ”,于是只好继续百度。

一番查找后,小老板了解到,电脑里的应用程序,一般由多个进程组成,而每个进程又由多个线程组成。而浏览器中 JS 脚本的执行,就是一个线程负责,就是JS 引擎线程

3. 小老板又重新定义了问题:“说说浏览器中JS 引擎线程的运行机制?”

小老板悟性很高,立马想到,要深入去解析JS 引擎线程的运行机制,不如先了解一下,包含这个线程的进程是如何运行的。

这时小老板了解到浏览器的进程都有哪些了,其中JS 引擎线程就在渲染进程里面:

  • Browser进程
    • 浏览器的主进程(负责协调、主控),该进程只有一个
    • 负责浏览器界面显示,与用户交互。如前进,后退等
    • 负责各个页面的管理,创建和销毁其他进程
    • 将渲染(Renderer)进程得到的内存中的Bitmap(位图),绘制到用户界面上
    • 网络资源的管理,下载等
  • 第三方插件进程
    • 每种类型的插件对应一个进程,当使用该插件时才创建
  • GPU进程
    • 该进程也只有一个,用于3D绘制等等
  • 渲染进程
    • 即通常所说的浏览器内核(Renderer进程,内部是多线程)
    • 每个Tab页面都有一个渲染进程,互不影响
    • 主要作用为页面渲染,脚本执行,事件处理等

4. 小老板又又重新定义了问题:“说说浏览器中渲染进程JS 引擎线程的运行机制?”

啥都不懂的小老板,只好继续百度了。先查一下渲染进程什么时候会工作。

简单了解了下浏览器中输入 url 到出现页面,发生的一系列反应:

  1. DNS 查询
  2. TCP 连接
  3. HTTP 请求即响应
  4. 服务器响应
  5. 客户端渲染

为了解答问题,小老板现在丝毫不关心前4点浏览器究竟干了什么。很显然第5点才是渲染进程用武之地。比如在第4点的时候,服务器响应了下面的html文件。

<!-- 态度温和的小老板 -->
<!DOCTYPE html>
<html lang="en">
  <script>alert('Fire in the hold!')</script>
  <body>
    <div>Son of Bittch!</div>
  </body>
</html>
复制代码

然后小老板又先进一步了解渲染进程具体的工作步骤:

  1. 处理 HTML 标记并构建 DOM 树
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 将各个节点绘制到屏幕上。

以及渲染进程中的两个比较重要的线程:

  1. GUI渲染线程
    • 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等
  2. JS引擎线程
    • JS引擎线程就是JS内核,负责处理Javascript脚本程序
    • GUI渲染线程与JS引擎线程是互斥的,JS 引擎线程会阻塞GUI渲染线程

小老板结合渲染进程的工作步骤和两个关联的线程分析得知:在解析上面的 html 文件的时候,JS 引擎线程会在第1点步骤的时候发挥作用,也就是GUI渲染进程解析到<script>alert('Fire in the hold!')</script>时,直接交给了JS 引擎线程处理了。(终于来到主角了。JS 执行阻塞DOM构建,小老板先放一边不管了)。

4. 小老板再次总结,又又又重新定义了问题:“说说浏览器中渲染进程JS 引擎线程的运行<script>alert('Fire in the hold!')</script>的机制?”

小老板想了一下,这有啥好说的,既然是单线程,代码只能一行接一行的执行。就直接弹窗 Fire in the hold! 呗。

这时,小老板意识到问题应该没那么简单。连夜学了几句 JS:

setTimeout(() => {
  console.log(0);
}, 1000);
new Promise((resolve) => {
  console.log(1);
  resolve();
}).then(() => {
  console.log(2);
});
console.log(3);
复制代码

好家伙,打印顺序是:1320。根本不讲武德,说好的按顺序执行呢?

小老板这里理性分析了一波:受限于单线程JS 引擎线程只能同步执行脚本,这一点他确凿无疑。之所以不按顺序打印,肯定是执行的顺序变了。是什么导致执行的顺序改变呢?小老板经过百度得知,原来是JS 引擎线程的执行机制:Event Loop

5. 小老板再次归纳问题:“说说浏览器中渲染进程JS 引擎线程Event Loop的执行机制”

啥都不懂的小老板,经过多番研究(百度)。明白了Event Loop的机制的一些缘由。

  1. 为啥要用Event Loop执行机制。

    比如有个需求,需要点击页面后,领取红包。比如实现的脚本代码如下:

    click(document.body) // 没有 Event Loop 的 JS,会卡住在这里,一直等待用户的点击
    alert("Fuck you man!")
    click(document.body) // 没有 Event Loop 的 JS,用户只能任由程序的摆布。
    alert("给,你的红包!")
    复制代码

    小老板对只能 “同步执行的JS” 卧槽了一句:“你在教我做事?” 小老板只能按照脚本的顺序操作,不然页面就卡住,毫无用户体验。为此Event Loop执行机制,应运而生!!

  2. Event Loop机制原理。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享