浏览器渲染步骤
浏览器渲染大致分为以下四个步骤:
1. 构建 DOM 树
• 过程:当浏览器接收到 HTML 文档后,会从上到下依次解析 HTML 代码。每遇到一个开始标签,就会创建一个对应的 DOM 节点,并根据标签的嵌套关系将这些节点连接起来,形成一个树状结构,即 DOM 树。例如,对于 <div><p>段落文本</p></div> 这段 HTML 代码,浏览器会先创建一个 div 节点,然后创建一个 p 节点,并将 p 节点作为 div 节点的子节点。
• 作用:DOM 树是文档内容的结构化表示,它为后续的样式计算、布局和绘制等操作提供了基础。通过 DOM 树,浏览器可以方便地访问和操作文档中的各个元素,比如获取元素的属性、修改元素的内容等。
2. 构建 CSSOM 树
• 过程:浏览器在解析 CSS 代码(包括内联样式、内部样式表和外部样式表)时,会将 CSS 规则转换成 CSS 对象模型(CSSOM)树。CSSOM 树的节点对应 CSS 选择器和样式规则。例如,对于 CSS 规则 .class { color: red; font-size: 14px; },浏览器会创建一个 CSSOM 节点,该节点包含选择器 .class 和对应的样式属性 color 与 font-size。
• 作用:CSSOM 树定义了文档中各个元素的样式信息。有了 CSSOM 树,浏览器才能知道每个元素应该应用哪些样式,从而在后续步骤中准确地呈现元素的外观,如颜色、字体大小、边距等。
3. 构建渲染树
• 过程:浏览器将 DOM 树和 CSSOM 树结合起来,生成渲染树。渲染树的节点称为渲染器(Renderer),每个渲染器包含 DOM 节点的可见内容和样式信息。在构建渲染树时,浏览器会遍历 DOM 树,对于每个可见的 DOM 节点(如元素节点、文本节点等),根据 CSSOM 树中对应的样式规则为其创建渲染器,并将这些渲染器按照文档流的顺序连接起来形成渲染树。例如,对于一个包含文本内容的 div 元素,浏览器会为其创建一个渲染器,该渲染器包含 div 元素的样式(如宽度、高度、背景颜色等)和文本内容。
• 作用:渲染树是浏览器进行布局和绘制的依据。它只包含可见的元素及其样式信息,不包括那些不可见的元素(如 display: none 的元素)。通过渲染树,浏览器能够确定每个元素在页面上的位置、大小等布局信息,以及如何将这些元素绘制到屏幕上。
4. 布局与绘制
• 布局(Reflow):
• 过程:浏览器根据渲染树中的节点信息,计算每个元素在页面上的确切位置和尺寸。这个过程会受到多种因素的影响,如元素的宽度、高度、边距、内边距、定位方式等。例如,对于一个块级元素,浏览器会根据其父元素的宽度、自身的宽度设置(如百分比宽度、固定宽度等)以及左右边距等因素,计算出该元素在水平方向上的位置和宽度;在垂直方向上,会根据其上一个兄弟元素的位置以及自身的高度等属性,确定其位置。
• 作用:布局是确保页面元素按照预期的结构和样式排列在页面上的关键步骤。只有经过精确的布局计算,浏览器才能知道每个元素占据的空间大小和位置,为后续的绘制工作提供准确的坐标信息。
• 绘制(Repaint):
• 过程:在布局完成后,浏览器开始绘制页面。绘制是将渲染树中每个节点的可见内容(如文本、图片、颜色、边框等)绘制到屏幕上。浏览器会按照渲染树的顺序,依次将各个元素的绘制内容合成在一起,形成最终的页面视图。例如,对于一个带有背景颜色和边框的 div 元素,浏览器会先绘制背景颜色,然后绘制边框,最后将文本内容绘制在相应的位置上。
• 作用:绘制是用户能够看到页面内容的最后一步。通过绘制,浏览器将计算好的布局信息和样式信息转化为可视化的页面,呈现在用户的屏幕上,让用户能够看到完整的网页内容。
HTTP 1.0/1.1/2.0/3.0、HTTPS的特性
HTTP 1.0:
- 确定了协议是无状态的,即同一客户端每次请求都没有任何关系
- 消息结构包含请求头和请求体
HTTP 1.1:
- 引入了持久连接,即 TCP 连接默认不关闭,可以被多个请求复用
- 在同一个 TCP 连接里面,客户端可以同时发送多个请求
- 虽然允许复用 TCP 连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的,服务器只有处理完一个请求,才会接着处理下一个请求。
- 新增了一些请求方法(如 PUT、DELETE 等)、新增一些请求头和响应头
HTTP 2.0:
- 采用二进制格式而非文本格式
- 完全多路复用,而非有序并阻塞的、只需一个连接即可实现并行
- 使用报头压缩,降低开销
- 支持服务器推送
HTTP 3.0
- 弃用 TCP 协议,采用一种新的更快的网络协议 QUIC(基于 UDP 协议)
HTTP状态码
以下是常见的HTTP状态码:
- 1xx:信息性状态码,表示请求已被接收,继续处理。
- 100:继续
- 101:切换协议
- 2xx:成功状态码,表示服务器成功接收、理解并处理了请求。
- 200:OK
- 201:已创建
- 202:已接受
- 204:无内容
- 206:部分内容
- 3xx:重定向状态码,表示需要进一步操作才能完成请求。
- 301:永久重定向
- 302:临时重定向
- 304:未修改
- 4xx:客户端错误状态码,表示服务器无法处理请求。
- 400:错误的请求
- 401:未授权
- 403:禁止访问
- 404:资源未找到
- 405:通常是因为服务器未配置允许使用该方法,或者该方法与服务器不兼容导致的
- 5xx:服务器错误状态码,表示服务器在处理请求时发生错误。
- 500:服务器内部错误
- 502:错误的网关
- 503:服务不可用
- 504:网关超时
除了以上常见的状态码外,还有其他一些状态码用于表示不同的情况和错误,例如429表示请求过多,418表示I'm a teapot等。
每个状态码都有特定的含义,用于指示请求的处理状态。
协商缓存与强制缓存
概念
1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码;
2.协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
两者的共同点是,都是从客户端缓存中读取资源;区别是强缓存不会发请求,协商缓存会发请求。
浏览器缓存过程:
- 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;
- 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;
- 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
- 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;
- 很多网站的资源后面都加了版本号,这样做的目的是:每次升级了 JS 或 CSS 文件后,为了防止浏览器进行缓存,强制改变版本号,客户端浏览器就会重新下载新的 JS 或 CSS 文件 ,以保证用户能够及时获得网站的最新更新。
进程与线程
- 从本质上说,进程和线程都是 CPU 工作时间片的一个描述:
- 进程描述了 CPU 在运行指令及加载和保存上下文所需的时间,放在应用上来说就代表了一个程序。
- 线程是进程中的更小单位,描述了执行一段指令所需的时间。
- 进程是资源分配的最小单位,线程是CPU调度的最小单位。
- 进程和线程之间的关系有以下四个特点:
- (1)进程中的任意一线程执行出错,都会导致整个进程的崩溃。
- (2)线程之间共享进程中的数据。
- (3)当一个进程关闭之后,操作系统会回收进程所占用的内存, 当一个进程退出时,操作系统会回收该进程所申请的所有资源;即使其中任意线程因为操作不当导致内存泄漏,当进程退出时,这些内存也会被正确回收。
- (4)进程之间的内容相互隔离。 进程隔离就是为了使操作系统中的进程互不干扰,每一个进程只能访问自己占有的数据,也就避免出现进程 A 写入数据到进程 B 的情况。正是因为进程之间的数据是严格隔离的,所以一个进程如果崩溃了,或者挂起了,是不会影响到其他进程的。如果进程之间需要进行数据的通信,这时候,就需要使用用于进程间通信的机制了。
js脚本缓存defer 和 async区别
defer 和 async是什么:
在HTML中,
为了改善这种阻塞行为,有两个属性可以用来异步加载JavaScript脚本:defer 和 async。
1. async:
-
- 当 async 属性被设置时,浏览器会异步加载脚本,并且不保证脚本的执行顺序与它们在文档中的出现顺序一致。
- 脚本一旦可用就会被执行,无论它是否在文档解析完成之后。这意味着如果多个带有 async 的脚本同时加载,它们可能以任意顺序完成,这取决于哪个脚本先下载完成。
- 由于 async 脚本不会阻塞页面渲染,通常建议用于那些不是严格依赖于页面其他部分初始化完成才能执行的独立功能脚本。
2. defer:
-
- 当 defer 属性被设置时,浏览器也会异步加载脚本,但与 async 不同的是,它会确保脚本按照在文档中出现的顺序执行,且总是在DOMContentLoaded事件触发之前执行,即在文档解析完成后,但在所有CSSOM计算和渲染之前。
- 多个带有 defer 属性的脚本会按照它们在文档中定义的顺序执行,这对于那些需要遵循特定执行顺序的脚本来说非常有用。
总结:
- async: 异步加载,执行顺序不确定,不阻塞DOM构建,一旦下载完成立即执行。
- defer: 也异步加载,但保证执行顺序与脚本在文档中的顺序一致,同样不阻塞DOM构建,但在DOMContentLoaded事件之前按序执行。
基于服务端的信息推送:Server Send Event(sse)
实现原理:
只要 http 返回 Content-Type 为 text/event-stream 的 header,就可以通过 stream 的方式多次返回消息了。
它传输的是 json 格式的内容,可以用来传输文本或者二进制内容。
// 这个 EventSource 是浏览器原生 api,就是用来获取 sse 接口的响应的,它会把每次消息传入 onmessage 的回调函数。
useEffect(() => {
const eventSource = new EventSource('http://localhost:3000/stream');
eventSource.onmessage = ({ data }) => {
console.log('New message', JSON.parse(data));
};
}, []);
如何监控用户页面卡顿
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 100) {
console.log('上报到数据中心');
}
});
observer.observe({
entryTypes: ['longtask'], // 任务名称数组
});