JS运行机制(浏览器篇)

本文主要根据网上资源总结而来,如有不对,麻烦指正,谢谢!


浏览器是多进程的

最新的Chrome浏览器包括:浏览器主进程,GPU进程,网络进程,渲染进程,和插件进程等。

  1. Browser进程: 浏览器的主进程,只有一个。控制浏览器除标签页外的界面,负责浏览器界面显示,与用户交互,如前进,后退等。
  2. 渲染进程: 默认一个标签页一个渲染进程(特殊情况下,渲染进程不一定每个标签页就一个,比如同一站点的页面间跳转就可能重用渲染进程。),主要的作用为页面渲染,脚本执行,事件处理等。
  3. 其他的就不叙述了。

进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
进程与进程之间完全隔离,相互独立,因此一个进程如果崩溃了或者挂起了,是不会影响到其他进程的。 一个进程中的多个线程可以读写进程的公共数据。

渲染进程是多线程的

GUI渲染线程: GUI(图形用户界面),该线程负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、合成render渲染树(DOM树 + CSSOM树)、布局计算和绘制页面。(注意,GUI渲染线程与JS引擎线程是互斥的,当其中一个线程执行时,另一个线程就会挂起。互斥的原因是JS也可以操作DOM,如果JS引擎线程和GUI线程同时操作DOM,结果就混乱了,渲染线程前后获得的元素数据就可能不一致了。)
JS引擎线程: 负责分析、预编译和执行JS(一个tab页中只有一个JS引擎线程)。
事件触发线程: 事件触发线程管理着一个任务(回调)队列,负责将满足条件的事件放进任务队列的队尾(如鼠标点击事件,定时器回调等),等待JS引擎的处理。
计时器线程: 指setInterval和setTimeout,因为JS引擎是单线程的,因此通过单独线程来计时。计时完毕后,计时器线程将回调事件给到事件触发线程,将它加到任务队列里面去。
异步http请求线程: 发起http请求时会开启一条线程请求,当检测到状态变更时,如果有回调函数,会通知事件触发线程,然后将这个事件(回调)放入任务队列中等待执行。

js引擎执行过程 主要分为三个阶段,分别是语法分析,预编译和执行阶段。
语法分析:分析该js代码块的语法是否存在基本的语法错误。
预编译:创建执行上下文、创建变量对象、建立作用域链、确定this指向等。

JS为什么会是单线程的语言?

为了防止DOM操作的冲突从而导致渲染出现不可预期的结果。

JS阻塞页面加载

由于GUI渲染线程与JS引擎线程互斥, 当JS引擎执行时GUI线程会被挂起,如果JS执行时间过长就会阻塞页面渲染,出现长时间白屏,影响用户体验。
然而浏览器提供了一些JS引擎不具备的特性,DOM API、定时器、HTTP请求等,可以用来实现异步、非阻塞的行为。

WebWorker

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。
限制:

  1. Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
  2. Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,需要以特定的方式通信。

任务队列和Event Loop

JS分为同步任务和异步任务

  • 同步任务: 同步任务都在主线程(JS引擎线程)上执行,形成一个执行栈,同步任务只有前一个任务执行结束,才能执行下一个任务。
  • 异步任务: 当异步任务执行结束,会将事件(回调)放入到任务队列,等待执行。一旦执行栈中的所有同步任务执行完毕,就会依次读取任务队列中的事件(回调)。
  • 任务队列则分为宏任务队列(Task Queue)和微任务队列(Job Queue)。
    在新ECMAScript标准中,宏任务(macrotask)和微任务(microtask)被分别称为 task 与 jobs。
  • 宏任务(macrotask): script,DOM API、定时器、HTTP请求等。
  • 微任务(microtask): Promise.then、MutationObserver,process.nextTick(node)等。
    (注意: 1. MutationObserver优先级小于Promise,用来监听DOM树的变更。 2. 在node环境下,process.nextTick的优先级高于Promise。)

JS执行任务的顺序:

  1. 执行同步任务(执行栈为空且微任务队列也为空时,script内的整块代码被作为宏任务的事件回调放入执行栈中执行)。
  2. 遇到异步任务则把它们放到非JS引擎线程上执行,当异步任务执行结束,会将事件(回调)放入到对应的队列中,即:宏任务队列和微任务队列,等待执行。
  3. 继续执行同步任务,如果遇到异步任务则执行过程2 ,直到同步任务全部执行完(JS执行栈被清空)。
  4. 检查微任务队列中是否有可执行的事件,如果有,依次取微任务队列中的事件放入到执行栈中执行,如果遇到异步任务则执行过程2。往复执行过程4,直到微任务队列清空
  5. 渲染UI,继续下一轮循环。
  6. 检查宏任务队列中是否有可执行的事件,如果有,取队列中最前面的事件放入到执行栈中执行,如果遇到异步任务则执行过程2,直到当前事件执行结束。
  7. 继续执行过程4、5、6,直至宏任务队列和微任务队列都为空。

概括: 宏任务(script)=> 所有微任务 => 渲染 => 宏任务 => ……

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值