浏览器内部结构

一、核心线程

浏览器是一个多进程多线程的系统,它会有一个主进程进行任务的调度。有一个第三方插件进程,避免插件崩溃时影响页面内容。然后每个 tab 页面都是一个单独的进程,每个 tab 进程中又有以下几个重要的线程:

  • GUI 渲染线程
  • JS 引擎线程
  • 定时器线程
  • 异步请求线程
  • 事件触发线程

1.1 GUI 渲染线程

  • 主要负责页面的渲染,包括解析 HTML,CSS,构建 DOM 树 -> CSS 规则树 -> 渲染树,最后计算元素的位置、渲染,回流、重绘等
  • 当执行 JS 引擎线程时,GUI 渲染线程会被挂起,当任务队列空闲时,GUI 线程恢复执行

1.2 JS 引擎线程

  • 该线程主要负责解析、执行 js 脚本

1.3 定时器线程

  • 该线程负责执行定时器任务,如 setTimeout、setInterval(如果放在主线程计时,受限于 js 单线程,计时会不准)
  • 主线程逐行执行代码到异步任务时,会将定时器任务交给该线程处理。等到计时结束,事件触发线程会将回调函数加入到任务队列尾部,等待 JS 引擎线程执行

1.4 异步请求线程

  • 负责执行异步请求,如 ajax、promise、http
  • 主线程逐行执行代码到异步请求时,会异步任务交给该线程处理。等到异步任务的状态码变更时,事件触发线程会将回调函数加入到任务队列尾部,等待 JS 引擎线程执行

1.5 事件触发线程

主要负责将准备好的事件加入到任务队列,如 setTimeout 回调、ajax 回调

二、事件循环 Event Loop

2.1 宏任务与微任务

先来道题

console.log('开始')
Promise.resolve().then(()=>{
  console.log('Promise1')
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
})
setTimeout(()=>{
  console.log('setTimeout1')
  Promise.resolve().then(()=>{
    console.log('Promise2')
  })
},0)

先揭晓答案

  1. 开始
  2. Promise1
  3. setTimeout1
  4. Promise2
  5. setTimeout2 

这是视频讲解

JS 中的事件循环

这里注意以下几点即可

  • 首先遇到同步任务,压入执行栈
  • 遇到微任务压入微任务队列
  • 遇到宏任务压入宏任务队列
  • 所有的同步任务相当于一个宏任务,而一个宏任务执行完成之后,需要把微任务队列中的全部任务全部执行

三、Node 中的事件循环

先注意一点,不管是浏览器中的事件循环还是 node 中的事件循环,都不是 JS 引擎去实现的,而是浏览器和 node 自己实现的东西。

所以即使 chrome 和 node 都用了 V8 引擎,可是二者的事件循环却完全不是一回事,实现的逻辑也是大相径庭。

node 中的事件循环是在 libuv 中实现的,libuv 是一个聚焦于 I/O 的库,一个基于事件驱动的跨平台抽象层,封装了不同系统底层一些特性,对外提供统一的 API。

 node.js 的运行机制大致如下:

V8 引擎解析 js 代码

调用 node API

libuv 负责执行 node API,

参考文章:https://www.jianshu.com/p/5f1a8f586019

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章