FirstPaint

JS阻止冒泡:event.stopPropagation(),一个事实,Parse HTML和evaluate script不会互相阻塞。

1.问题一:页面基本渲染流程是什么样的?

当我们在浏览器输入一个域名后接下来执行哪些流程?可以看一下下面这张图来加强理解:

根据域名获取资源的流程

挑几个重点的(看得懂英文单词)进行解释,1.DNS查询,获取表示该资源的域名所在机器的IP地址;2.SSL阶段,如果走的是HTTPS协议的话,那么就需要验证HTTPS证书的有效性,这时会处于SSL阶段;3.Request Send阶段,此时浏览器会发起Request Send事件;4.TTFB阶段,TTFB的全称叫做Time To First Byte,是指当浏览器发起请求后开始收到第一个字节的等待时间,TTFB反映出了服务端对请求的响应能力,对于TTFB可以这样打个比方加强理解:A向B问了一个问题,B思考了3S之后,开始回答给A听,这里的3S就相当于TTFB时间。5.Content Download阶段,很显然就是字面意思上面所说的那样,就是响应数据的下载时间。

当浏览器接收到请求数据后,会触发receive response,然后在触发receive data事件,接着触发finish loading事件。当触发finish loading之后,如果是HTML文档的话,那么接着执行Parse HTML事件,对于HTML文档来说,通常还会有一些外部资源比如css文档和js脚本文件,那么此时又重复之前的步骤,send request , receive response , receive data , 如果是接收到的文件是css文件的话,那么是在触发receive data事件之后便开始执行Parse Stylesheet阶段,在Parse Stylesheet阶段完成后,才会触发finish loading事件。

如果接收到的文件是js文件的话,那么接下来和HTML一样,receive response -> receive data -> finish loading -> evaluate script。

2.问题三:DOMContentLoaded和onLoad事件分别在什么时机被触发?

DOMContentLoaded事件一般在parse HTML过程完成后被触发(解析到了HTML文档的末尾)。onLoad一般需要等到外部资源也已经加载完成了的时候触发。

3: DOMContentLoaded和onload事件一般是谁写被触发?

正常生产情况大部分都是DOMContentLoaded事件先被触发。但是也不一定,当浏览器finish loading HTML文档后,接着会开始parse HTML,但是呢,parse HTML并不是直接就到HTML文档结尾的,而是分阶段的:先parse HTML到然后停止,然后在继续从终止的地方继续parse HTML到末尾。前面也提到了DOMContentLoaded事件是parse html到了末尾才会可能被触发,如果解析到body都还没有发现外部引用资源的话,那么自然就是先触发onload事件,接着触发DOMContentLoaded事件。

3-1:DOMContentLoaded和onload事件,谁先被触发,谁的callback就先被执行吗?

Chrome下测试结果,哪怕先触发onload事件,DOMContentLoaded的回调方法也一定会先比onload事件的回调方法更早执行。

4.问题四:内嵌css和外部css的流程有什么区别?

对于内嵌CSS(写在页面HTML文件中的style标签内)来说,浏览器自然不会发起send request,receive response,receive data,finish loading这几个事件的,那么问题来了,会触发parse stylesheet事件吗?答案是不会的,而这就是内嵌CSS和外部CSS资源的区别之一。对于内嵌css来说,相关的事件有可能就只是recalculate style了。

7.问题七:对于浏览器来说,哪些关键过程是单线程,哪些是多线程的?

浏览器中的js解释器引擎是单线程的,浏览器内核本身是多线程的,每个页面通常都是由下面几个线程组成的:

  • 1.GUI渲染线程
  • 2.js引擎线程
  • 3.事件触发线程
  • 4.异步HTTP线程
  • 5.EventLoop轮询的处理线程

8:写在head里面的css link是否会阻塞Parse html过程?

本质:如果script阻塞页面的parse HTML的话,并且head里面有link标签的话,那么evaluate script就会在parse stylesheet之后。那么那些行为下的script会阻塞页面的parse HTML过程呢?head中的script,body中的script。但是需要注意的是,尽管在没有css的情况下,body中的inline script不会阻塞parse HTML过程,但是呢只要存在样式设置的话(inline style或者link),那么此时会阻塞parse HTML过程,evaluate script会在parse stylesheet之后。同时,如果head中的inline script所出现的位置在link的后面的话,那么此时也会阻塞parse HTML过程,并且evaluate script会在parse stylesheet之后。

8-1:在没有script的情况下,写在body里面css link会阻塞parse HTML吗?

**会的,在没有script的情况下,写在body里面的css link会阻塞parse HTML过程,在说清楚一些,只是资源的网络加载过程阻塞了parse HTML的过程,当这些样式link的finish loading被触发之后的parse stylesheet是不会阻塞parse HTML的,两个工作流程之间并不会相互阻塞。同时parse HTML和recalculate style之间也是不会相互阻塞的。值得一提的是,如果有多个外部样式link的话,那么并不是每触发某个link的finish loading之后便会立马触发parse stylesheet过程。

8-2:总结,对于下面的代码,考虑阻塞parse HTML的情况:

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html>
<html lang="zh">
<head>
<title>test</title>
<meta charset="utf-8" />

<script type="text/javascript">
setTimeout(function () {
console.log('setTimeout');
}, 0);

new Promise((resolve, reject) => {
resolve(1);
}).then(n => {
console.log(n);
})

console.log('1');

window.addEventListener('load', () => {
console.log('window onload');
});

window.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoaded');
});
</script>
<style type="text/css">
.container {
width: 300px;
height: 300px;
margin: 10%;
border: 1px solid green;
}
.out {
width: 1000px;
height: 1000px;
background: orange;
}
</style>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/findAndReplaceDOMText/0.4.6/findAndReplaceDOMText.min.js"></script> -->

<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui-calendar/0.0.8/calendar.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/picnic/6.5.0/picnic.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/wingcss/0.1.9/wing.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/react-instantsearch-theme-algolia/4.5.2/style.min.css" /> -->
</head>
<body>
<!-- <style type="text/css">
.container {
width: 300px;
height: 300px;
margin: 10%;
border: 1px solid green;
}
.out {
width: 1000px;
height: 1000px;
background: orange;
}
</style> -->
<!-- <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap-grid.css" rel="stylesheet"> -->

<div class="out">
<div class="container"></div>
<!-- <video src="https://gk-news.oss-cn-beijing.aliyuncs.com/20187220/%E9%BD%90%E8%80%81%E5%B8%88%20720p%E4%BF%AE%E6%94%B9.mp4"></video> -->
</div>
<div>
a
</div>


<p>hello script</p>
</body>
</html>

Chrome下情况大致如下:

测试场景 是否阻塞parse HTML onload,DOMContentLoaded,First Paint谁先被触发 首先被触发的事件的触发时间 FirstPaint被触发时间
没有js,head中写style标签 不阻塞 onload > DOMContentLoaded > FirstPaint ~94ms ~105ms
没有js,head中写link 不阻塞 DOMContentLoaded > onload > FirstPaint ~86ms ~764ms
没有js,body中写style 不阻塞 onload > DOMContentLoaded > FirstPaint ~59ms ~81ms
没有js,body中写link 阻塞 DOMContentLoaded > FirstPaint > onload ~524ms ~616ms
没有css,head中写inline script 不阻塞 onload > DOMContentLoaded > FirstPaint ~59ms ~85ms
没有css,head中写script 阻塞 onload > DOMContentLoaded > FirstPaint ~356ms ~366ms
没有css,body里面写inline script 不阻塞 onload > DOMContentLoaded > FirstPaint ~85ms ~91ms
没有css,body里面写script 阻塞 onload > DOMContentLoaded > FirstPaint ~361ms ~365ms
head中写style标签和inline script 不阻塞 onload > DOMContentLoaded > FirstPaint ~81ms ~109ms
head中写style标签和script 阻塞 onload > DOMContentLoaded > FirstPaint ~921ms ~927ms
head中写link标签和inline script 不阻塞 DOMContentLoaded > onload > FirstPaint ~88ms ~394ms
head中写link标签和script 阻塞 evaluate script 一定是会在 所link的css资源的parse stylesheet之后 ~393ms ~399ms
body中写style标签和inline script 不阻塞 onload > DOMContentLoaded > FirstPaint ~73ms ~111ms
body中写style标签和script标签 阻塞 DOMContentLoaded > onload > FirstPaint ~357ms ~353ms
body中写link标签和inline script 阻塞 DOMContentLoaded > onload > FirstPaint ~395ms ~400ms
body中写link标签和script标签 阻塞 DOMContentLoaded > onload > FirstPaint ~425ms ~431ms
head中写link,body中script 阻塞 evaluate script 一定是会在 所link的css资源的parse stylesheet之后 未记录 未记录
head中写style,body中script 阻塞 recaluate style 通常会在 evaluate script之前 未记录 未记录
head中写link,body中inline script evaluate script 会被link的css资源给阻塞 未记录 未记录
head中写style,body中inline script 不阻塞 onload > DOMContentLoaded > FirstPaint 未记录 未记录

问:为什么外部资源script不推荐写在head标签里面?

默认的(不加async或者defer),那么不仅网络加载过程会阻塞parse HTML过程,而且当script资源的finish loading事件被触发后,其evaluate script过程也会阻塞parse HTML过程。

10.问题10:parse html和parse stylesheet在浏览器中可以并发执行吗?

可以的,他们之间不会互相阻塞。evaluate script也可以不阻塞parse stylesheet。