学习目标

理解:

JavaScript 为什么能够调用浏览器提供的各种能力?

例如:

1
2
3
4
5
6
7
8
9
document.querySelector()

setTimeout()

fetch()

requestAnimationFrame()

addEventListener()

这些 API 为什么 JavaScript 可以直接使用?

答案:

因为浏览器 Runtime 提供了 Binding 层,把 JavaScript 世界连接到浏览器 C++ 实现。


一、浏览器不是只有 V8

浏览器内部包含多个模块。

大致:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Browser Process

|
|
Renderer Process

|
|
Runtime
|
├── V8
|
├── Blink
|
├── Scheduler
|
├── Network Interface
|
├── Storage
|
└── Other Web APIs

V8 的职责

V8 负责:

  • JavaScript 语法
  • 执行 JS
  • JS 对象
  • Function
  • Promise
  • Array
  • Map
  • Set
  • GC

但是:

V8 不知道:

1
2
3
4
5
DOM
CSS
网络
定时器
页面渲染

例如:

1
document

这个对象不是 V8 创建的。


Browser Runtime 的职责

Browser Runtime 提供:

  • 页面能力
  • Web API
  • 浏览器环境能力

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
DOM

Timer

Fetch

Event

Canvas

Storage

Animation

二、Binding Layer 是什么

Binding Layer:

就是:

JavaScript API 和浏览器 C++ 实现之间的桥梁。

模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
JavaScript

↓

V8

↓

Binding Layer

↓

C++ Runtime Implementation

↓

具体模块

三、为什么需要 Binding

因为:

V8 和浏览器能力属于两个世界。


V8:

1
2
3
4
5
6
7
8
9
10
11
纯 JavaScript Runtime

不知道:

网页

DOM

网络

窗口

Browser Runtime:

1
2
3
4
5
6
7
8
9
10
11
12
13
C++ 实现

知道:

DOM

CSS

网络

事件

渲染

所以需要:

1
2
3
4
5
6
7
8
9
JS API

↓

Binding

↓

C++对象/方法

四、DOM 是 Binding 的一个例子

例如:

1
2
3
const div = document.querySelector("#box");

div.style.color = "red";

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
JavaScript

↓

V8

↓

DOM Wrapper

↓

Binding

↓

Blink Element(C++)

↓

修改 Style

↓

Style Recalculate

↓

Layout

↓

Paint

↓

Composite

注意:

JavaScript 操作的不是 DOM 本体。

而是:

Blink 对象在 JS 世界中的 Wrapper。


五、Wrapper(包装对象)

Wrapper:

表示:

浏览器 C++ 对象在 JavaScript 世界中的代理对象。

例如:

Blink:

1
Element*

对应:

JavaScript:

1
div

关系:

1
2
3
4
5
6
7
8
9
JavaScript Object

↓

Wrapper

↓

Blink::Element*

六、为什么需要 Wrapper

因为:

V8 管理的是 JS 对象。

Blink 管理的是 C++ 对象。

两个生命周期不同。

所以需要:

1
2
3
4
5
6
7
8
9
JS世界

↓

Wrapper

↓

C++世界

进行连接。


七、Wrapper Cache

浏览器保证:

1
2
3
4
5
const a = document.getElementById("box");

const b = document.getElementById("box");

a === b;

结果:

1
true

原因:

存在:

1
2
3
4
5
6
7
8
9
Blink Object

↓

Wrapper Cache

↓

JS Wrapper

第一次:

1
2
3
4
5
6
7
8
9
10
11
12
13
Blink找到对象

↓

没有Wrapper

↓

创建Wrapper

↓

缓存

第二次:

1
2
3
4
5
6
7
8
9
Blink找到对象

↓

查缓存

↓

返回已有Wrapper

八、Binding 不只连接 DOM

DOM 只是最直观案例。

实际上:

很多 Web API 都通过类似机制实现。


例子1:setTimeout

JavaScript:

1
setTimeout(fn,1000);

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
JS

↓

V8执行调用

↓

Binding

↓

Timer实现

↓

注册定时器

↓

时间到

↓

创建Task

↓

Event Loop执行回调

注意:

setTimeout 不是 ECMAScript 标准。

属于浏览器提供的 Web API。


例子2:fetch

JavaScript:

1
fetch("/api")

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
JS

↓

V8

↓

Binding

↓

Fetch API实现

↓

Network Service

↓

网络请求

↓

返回结果

↓

Promise resolve

↓

Microtask执行

例子3:事件监听

1
2
3
4
button.addEventListener(
"click",
handler
)

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
JS

↓

V8

↓

Binding

↓

Blink EventTarget

↓

保存监听器

↓

用户点击

↓

生成事件Task

↓

V8执行handler

例子4:requestAnimationFrame

1
requestAnimationFrame(callback)

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
JS

↓

V8

↓

Binding

↓

Browser Scheduler

↓

等待渲染时机

↓

执行callback

↓

进入渲染流程

九、完整 Browser Runtime 模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
              JavaScript

|

V8

|

Binding Layer

|

┌─────────────┼─────────────┐

▼ ▼ ▼

Blink Timer Network

| | |

DOM setTimeout Fetch

|

CSS

|

Layout

|

Paint

|

Composite

十、生命周期模型

浏览器对象生命周期由多个 Root 决定。

不是只看 JS。


JS Root

例如:

1
let div = document.querySelector("#box");

关系:

1
2
3
4
5
6
7
8
9
JS Root

↓

Wrapper

↓

Blink Object

Browser Root

例如 DOM Tree:

1
2
3
<body>
<div></div>
</body>

关系:

1
2
3
4
5
6
7
8
9
Document

↓

DOM Tree

↓

Element

所以:

对象是否释放:

取决于:

1
2
3
4
5
JavaScript Root

+

Browser Root

十一、完整调用链

例如:

1
div.style.color="red";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
JavaScript

↓

V8

↓

Binding

↓

Blink

↓

Style System

↓

Layout

↓

Paint

↓

Composite

↓

GPU

↓

Screen

例如:

1
fetch()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
JavaScript

↓

V8

↓

Binding

↓

Fetch API

↓

Network Service

↓

网络

十二、核心总结

1.

V8 负责执行 JavaScript,但不提供浏览器能力。


2.

Browser Runtime 提供 DOM、网络、定时器、事件等能力。


3.

Binding Layer 是 JavaScript 世界和浏览器 C++ 世界之间的桥梁。


4.

DOM 只是 Binding 的一个例子,setTimeout、fetch、事件、动画等 Web API 都属于这个模型。


5.

JavaScript 操作的通常不是浏览器真实对象,而是对应的 Wrapper。


6.

Wrapper Cache 保证同一个浏览器对象在 JS 世界中保持唯一映射。


当前整体浏览器模型(更新版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Browser Process

|

Renderer Process

|

Runtime

|

┌───────────────┐

▼ ▼

V8 Browser Runtime

| |

JS执行 Web API

| |

GC Binding

|

┌─────────┼─────────┐

▼ ▼ ▼

Blink Timer Network

|

Render Pipeline

|

GPU

|

Screen