基础知识
JavaScript是解释型语言
浏览器嵌入了JavaScript引擎(如V8)用于解释JavaScript代码,解释后由CPU来执行,渲染至页面
JavaScript Engine
- V8(Google): 由C++编写,开放源代码,由Google开发,是Google Chrome的一部分,也用于NodeJS
- JavaScriptCore(Apple): 开放源代码,用于webkit型浏览器,如Safari,2008年实现了编译器和字节码解释器,升级为了SquirrelFish。苹果内部代号为"Nitro"的JavaScript引擎也是基于JavaScriptCore引擎的。
- Rhino(Mozilla基金会): 由Mozilla基金会管理,开放源代码,完全以Java编写,用于HTMLUnit
- SpiderMonkey(Mozilla): 第一款JavaScript引擎,早期用于Netscape Navigator,现时用于Mozilla Firefox。
V8的实现原理
- 开始执行JavaScript代码
- V8解析源代码并将其转化为抽象语法树(AST)
- 基于该AST,Ignition解释器可以开始做它的事情,并产出字节码
- 同时开始运行代码并收集类型反馈
- 引擎可以检测到某些行为是否经常发生,以及使用的数据类型,为了使它运行得更快,字节码可以和反馈数据一起被发送到优化编译器。优化编译器在此基础上做出某些假设,然后产生高度优化的机器代码 [内联缓存技术(inline cashing)]
- 如果在某些时候,其中一个假设被证明是不正确的,优化编译器就会取消优化,并回到解释器
Compiler
AST
代码转为AST:
let a = "aaaa"
{
type: "Program",
body: [
{
type: "VariableDeclarator",
declarations: [{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "a"
},
init: {
type: "Literal",
value: "aaa",
raw: "aaa"
}
}],
kind: "let"
}
],
sourceType: "module"
}
执行上下文
函数或内容,代码在执行过程中需要分配存储空间,于是便有一个对象来表示当前的执行上下文
JavaScript始终在栈底存在一个全局上下文(Global Context)对象,当有其它上下文(函数)需要执行时,依次入栈,再依次出栈执行,执行至最后便仅剩全局上下文对象。
事件循环机制
JavaScript执行代码时,同步代码自上而下执行,异步代码分别进入微任务队列和宏任务队列等待执行。
在宏观上,把同步代码归为宏任务内容,但它不用进宏任务队列。
宏任务
JS每次从事件循环队列中取出一个宏任务执行,在执行过程中产生的宏任务将会放到事件循环队列中依次执行,每次执行栈执行的代码可以当作一个宏任务
- I/O(NodeJS里的一些文件操作、流)
- setTimeout
- setInterval
- setImmediate
- requestAnimationFrame
微任务
当前执行栈里的同步代码执行完后,会在渲染前,将执行期间所产生的所有微任务都执行完
- process.nextTick
- MutationObserver
- Promise.then/catch/finally
垃圾回收
垃圾回收常见的算法:
- 引用计数
- 标记清除
- 标记清除压缩
- Cheney算法,用在v8新生代垃圾回收