你不知道的 Webkit 内核(5000字,了解浏览器渲染原理)

图雀社区

共 6001字,需浏览 13分钟

 ·

2020-11-20 02:04

当下浏览器内核主要有 Webkit、Blink 等。本文分析注意是自 2001 年 Webkit 从 KHTML 分离出去并开源后,各大浏览器厂商魔改 Webkit 的时期,这些魔改的内核最终以 Chromium 受众最多而脱颖而出。本文就以 Chromium 浏览器架构为基础,逐层探入进行剖析。

引子

这里以一个面试中最常见的题目从 URL 输入到浏览器渲染页面发生了什么?开始。

这个很常见的题目,涉及的知识非常广泛。大家可先从浏览器监听用户输入开始,浏览器解析 url 的部分,分析出应用层协议 是 HTTPS 还是 HTTP 来决定是否经过会话层 TLS 套接字,然后到 DNS 解析获取 IP,建立 TCP 套接字池 以及 TCP 三次握手,数据封装切片的过程,浏览器发送请求获取对应数据,如何解析 HTML,四次挥手等等等等。这个回答理论上可以非常详细,远比我提到的多得多。

本文试图从浏览器获取资源开始探究 Webkit。如浏览器如何获取资源,获取资源时 Webkit 调用了哪些资源加载器(不同的资源使用不同的加载器),Webkit 如何解析 HTML 等入手。想要从前端工程师的角度弄明白这些问题,可以先暂时抛开 C++源码,从浏览器架构出发,做到大致了解。之后学有余力的同学再去深入研究各个底层细节。

本文的路线循序渐进,从 Chromium 浏览器架构出发,到 Webkit 资源下载时对应的浏览器获取对应资源如 HTML、CSS 等,再到 HTML 的解析,再到 JS 阻塞 DOM 解析而产生的 Webkit 优化 引出浏览器多线程架构,继而出于安全性和稳定性的考虑引出浏览器多进程架构。

一. Chromium 浏览器架构

Chromium浏览器架构

(Chromium 浏览器架构)

我们通常说的浏览器内核,指的是渲染引擎。

WebCore 基本是共享的,只是在不同浏览器中使用 Webkit 的实现方式不同。它包含解析 HTML 生成 DOM、解析 CSS、渲染布局、资源加载器等等,用于加载和渲染网页。

JS 解析可以使用 JSCore 或 V8 等 JS 引擎。我们熟悉的谷歌浏览器就是使用 V8。比如比较常见的有内置属性 [[scope]] 就仅在 V8 内部使用,用于对象根据其向上索引自身不存在的属性。而对外暴露的 API,如 __proto__ 也可用于更改原型链。实际上 __proto__ 并不是 ES 标准提供的,它是浏览器提供的(浏览器可以不提供,因此如果有浏览器不提供的话这也并不是 b ug)。

Webkit Ports 是不共享的部分。它包含视频、音频、图片解码、硬件加速、网络栈等等,常用于移植。

同时,浏览器是多进程多线程架构,稍后也会细入。

在解析 HTML 文档之前,需要先获取资源,那么资源的获取在 Webkit 中应该如何进行呢?

二.Webkit 资源加载

HTTP 是超文本传输协议,超文本的含义即包含了文本、图片、视频、音频等等。其对应的不同文件格式,在 Webkit 中 需要调用不同的资源加载器,即 特定资源加载器。

而浏览器有四级缓存,Disk Cache 是我们最常说的通过 HTTP Header 去控制的,比如强缓存、协商缓存。同时也有浏览器自带的启发式缓存。而 Webkit 对应使用的加载器是资源缓存机制的资源加载器 CachedResoureLoader 类。

如果每个资源加载器都实现自己的加载方法,则浪费内存空间,同时违背了单一职责的原则,因此可以抽象出一个共享类,即通用资源加载器 ResoureLoader 类。Webkit 资源加载使用了三类加载器:「特定资源加载器,资源缓存机制的资源加载器 CachedResoureLoader 和 通用资源加载器 ResoureLoader」

既然说到了缓存,那不妨多谈一点。

资源既然缓存了,那是如何命中的呢?答案是根据资源唯一性的特征 URL。资源存储是有一定有效期的,而这个有效期在 Webkit 中采用的就是 LRU 算法。那什么时候更新缓存呢?答案是不同的缓存类型对应不同的缓存策略。我们知道缓存多数是利用 HTTP 协议减少网络负载的,即强缓存、协商缓存。但是如果关闭缓存了呢?比如 HTTP/1.0 Pragma:no-cache 和 HTTP/1.1 Cache-Control: no-cache。此时,对于 Webkit 来说,它会清空全局唯一的对象 MemoryCache 中的所有资源。

资源加载器内容先到这里。浏览器架构是多进程多线程的,其实多线程可以直接体现在资源加载的过程中,在 JS 阻塞 DOM 解析中发挥作用,下面我们详细讲解一下。

三.浏览器架构

浏览器是多进程多线程架构。

对于浏览器来讲,从网络获取资源是非常耗时的。从资源是否阻塞渲染的角度,对浏览器而言资源仅分为两类:「阻塞渲染」如 JS 和 「不阻塞渲染」如图片。

我们都知道 JS 阻塞 DOM 解析,反之亦然。然而对于阻塞,Webkit 不会傻傻等着浪费时间,它在内部做了优化:启动另一个线程,去遍历后续的 HTML 文档,收集需要的资源 URL,并发下载资源。最常见的比如