学习目标

理解:

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