浏览器相关

300 阅读5分钟

进程线程

深入理解浏览器中的进程与线程 - 掘金

chrome 页面进程

职责
浏览器进程负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等
GPU进程负责整个浏览器界面的渲染。
网络进程负责发起和接受网络请求
插件进程主要是负责插件的运行
渲染进程负责控制显示tab标签页内的所有内容,核心任务是将HTML、CSS、JS转为用户可以与之交互的网页,默认情况下Chrome会为每个Tab标签页创建一个渲染进程

渲染进程

职责
GUI渲染线程负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、渲染树、和绘制页面,重绘重排也是在该线程执行
JS引擎线程一个tab页中只有一个JS引擎线程(单线程),负责解析和执行JS。它GUI渲染线程不能同时执行,只能一个一个来,如果JS执行过长就会导致阻塞掉帧。如 V8 引擎
计时器线程指setInterval和setTimeout,因为JS引擎是单线程的,所以如果处于阻塞状态,那么计时器就会不准了,所以需要单独的线程来负责计时器工作
异步 http 请求线程XMLHttpRequest连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待JS引擎空闲执行
事件触发线程负责将异步任务(如事件回调、Promise、XHR等)放入事件队列,以便在主线程空闲时执行。

常见浏览器 JS引擎 和 渲染引擎(内核)

JS引擎内核(渲染引擎)css 前缀
IEChakraTrident-ms-
EdgeV8Blink-ms-
SafariJavaScriptCore,又称 Nitro 或 SquirrelFish ExtremeWebkit-webkit-
ChromeV8Blink-webkit-
FirefoxSpiderMonkeyGecko-moz-

解析过程

网络请求:首先我们的浏览器会向服务器发起请求,以获取 HTML 文件。这包括 DNS 解析(将域名转换为服务器 IP 地址)、TCP 连接(通过三次握手与服务器建立连接)等过程。

加载资源:如果 HTML 文件中包含了其他资源,如 JavaScript、CSS 等,浏览器会再次发起请求以获取这些资源文件。在这个过程中,浏览器会首先检查本地是否有缓存文件,分为强缓存和协商缓存。

强缓存:如果命中强缓存,浏览器会直接从缓存中读取资源,而不会再次请求服务器。通常情况下,强缓存对应的 HTTP 响应码为 200。相关的 HTTP 头信息包括 cache-control(缓存控制,例如 max-age 表示有效期)和 expires(过期时间)。

协商缓存:如果命中协商缓存,浏览器会向服务器发送请求,但服务器会返回一个 304 状态码,表示资源未发生变动,可以直接从缓存读取。相关的 HTTP 头信息包括 last-modified(资源最后修改时间)和 etag(实体标签,资源的唯一标识符)。

解析:浏览器从上到下解析 HTML 文件,生成 DOM(文档对象模型)树。同时解析 CSS,生成 CSSOM(CSS 对象模型)树。之后,浏览器会将 DOM 树和 CSSOM 树合并,生成渲染树(Render Tree)。

渲染:根据渲染树,浏览器会进行布局计算,确定每个元素的位置和大小,接着进行绘制,将元素呈现到页面上。

css 怎么阻塞页面

css加载会造成阻塞吗? - 掘金

medium.com/jspoint/how…

image.png

上面 HTML 生成 DOM 树和 CSSOM 树生成是并行的,CSS 的加载并不会阻塞 DOM 树的构建,但是 CSS 加载会阻塞 Render Tree 的构建,从而阻塞页面渲染。

不影响构建

代码:

  <div>1</div>
  <div>1</div>
  <div>1</div>
  <div>1</div>
  <link rel="stylesheet" href="./red.css" type="text/css" />
  <div>2</div>
  <div>2</div>
  <div>2</div>
  <div>2</div>
/** red.css */
div{
  color: red;
}

将网速降到 Slow 3G 看效果哈:

前面4个dive默认显示黑色,没有受 css 文件下载的影响,先渲染出来,符合浏览器会尽早显示出内容给用户。 red.css 文件下载完成后,后面4个div才会渲染出来。

对 JS 的影响
  • css 文件没下载并解析完成之前,后续的 js 脚本不能执行。下面的 alert('ok') 在 css 下载并解析完成之前不会弹出来:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css"> 
<script> alert('ok') </script>
  • css 文件的下载不会阻塞前面的 js 脚本执行。下面的 alert('ok') 会在 css 下载完成前弹出:
<script> alert('ok') </script> 
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">

JS 怎么阻塞页面

fe.ecool.fun/topic-answe…

developer.aliyun.com/article/947…

developer.chrome.com/blog/inside…

内联

内联脚本会阻塞页面解析和渲染:

<p>Hello<p>
<script>
const now = Date.now()
while (Date.now() - now < 2000) {
}
</script>
<p>world</p>

内联脚本无论放在 head 标签中,还是放在 body 标签最后,页面解析和渲染都会被阻塞。 2秒后,页面才会渲染出来 hello 和 world 标签。

外联

我们知道 HTML 解析是从上向下进行的,当遇到外联的 script 标签(没有 async 和 defer )时页面解析和渲染会被中止,因为 Javascript 可以通过 document.write() 等操作 DOM 元素。JS 引擎线程和GUI渲染线程互斥,只会有一个线程运行。

<div>test-top</div>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<div>test</div>

页面会先渲染出来 test-top,等 jquery-3.4.1.js 文件完成下载后,才会显示 test。

说明外联 JS 会阻塞页面的解析和渲染,但是因为无法确定脚本中的内容,所以会优先渲染一次已经构建DOM,确保加载的脚本能取得最新的DOM

所以我们可以把外联 script 放在 body 最后,让用户尽早看见页面内容。

<div>test-top</div>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<div>test</div>

在网速 Slow 3G 看效果哈:

这就是说 为什么要把 script 外联放在 body 最后,这样可以保证页面在处理 JavaScript 代码之前完全渲染页面,缩短浏览器显示空白页面的时间,让用户觉得页面加载更快。

defer & async

易混淆的一些基础知识点 - 掘金