JS
Event Loop
浏览器
Event Loop 是 JavaScript 的执行机制,它是一个循环,不断地从任务队列中获取任务并执行。
JS 是单线程执行的,当遇到一些耗时操作,比如网络请求、定时器不会立即执行,而是放入到任务队列中,当主线程的代码执行完毕,在从任务队列中获取任务执行
- 微任务队列
- 宏任务队列
宏任务
- script
- 事件回调
- setTimeout
- setInterval
- requestAnimationFrame
微任务
- Promise.then
- MutationObserver
- queueMicrotask
执行顺序
主线程 > 微任务 > 宏任务
每次执行宏任务之前,需要确保微任务队列清空
- 如果宏任务中加入了微任务,那么需要先执行微任务,再执行宏任务
Node
Node 中的 Event Loop 是基于 libuv 实现的,简单来说相比浏览器而言,它会有 3 个 事件队列
- 2 个微任队列
- nextTick
- promise.then 或者其他微任务
- 1 个宏任务队列
- 宏任务分为 6 个 阶段 (一次 tick)
- timers
- pending callbacks
- idle, prepare
- poll
- check
- close callbacks
- 宏任务分为 6 个 阶段 (一次 tick)
执行顺序
主线程 > 微任务(nextTick > promise.then) > 宏任务
浏览器内核 (渲染引擎)
目前主流的浏览器内核有:
- Gecko 内核:Firefox
- Webkit 内核:Safari
- Blink 内核:Chrome
Webkit 内核
Webkit 内核分为两部分:
- WebCore:负责 HTML 的解析、布局、渲染等
- JavaScriptCore:负责 JavaScript 的解析、执行
V8 引擎
V8 引擎是 Google 开发的 JavaScript 引擎,它将 JavaScript 代码编译为机器码,并执行。
V8 引擎的执行过程
- 解析 JavaScript 代码,生成抽象语法树(AST)
- parse 词法分析、语法分析 最后生成 AST
- 将 AST 转换为字节码
- ignition(点火) 将 AST 转换为字节码
- 执行字节码
- turboFan (收集类型信息) 将字节码转换为机器码,提高执行效率
GC 内存
垃圾回收算法
引用计数
顾名思义,就是记录每个对象的引用次数,当引用次数为 0 时,就认为该对象是垃圾,可以被回收。
js
const info = { name: "ice" };
const obj = {
friend: info,
};
此时的 info 的引用次数就为 2,obj 的引用次数为 1
该算法不能解决循环引用问题
js
const a = {
f: b,
};
const b = {
f: a,
};
此时 a 和 b 的引用次数都为 1,无法被回收
标记清除
其核心思想是可达性,从根节点出发如果不能访问到该对象,就认为是垃圾
算法优化
- 标记整理,搬运到连续的内存中,避免内存碎片化,从而减少内存的浪费
- 分代收集
- 新生代
- 分为两个工作区,经过两轮标记后,存活的对象会被移动到老生代,diff 就被复制到另外一个工作区 (减少内存碎片)
- 老生代
- 长期存活的对象,减少检查次数
- 增量收集
- 将垃圾回收拆分为多个小任务,穿插在 JS 执行中执行,避免出现卡顿
- 闲时收集
- 在浏览器空闲时执行垃圾回收,避免影响用户体验