浏览器渲染页面的学习笔记

一、浏览器的进程与线程

JavaScript是单线程的,但是浏览器是多线程的,当我们使用Chrome浏览器打开一个网页时,浏览器会开启浏览器渲染进程来完成页面的渲染,该进程又包括多个线程:
1)GUI渲染线程,负责渲染浏览器界面元素,解析HTML、CSS、构建DOM树和RenderObject树、布局和绘制等,当界面需要回流或重绘时都会触发该线程;
2)js线程,执行js代码,与渲染线程互斥;
3)定时器触发线程,浏览器定时计数器,即setTimeout和setInterval所在的线程;
4)事件触发线程,用来管理事件循环,当一个事件被触发时,该线程就会把事件添加到待任务队列的队尾,等待js引擎的处理。
5)异步http请求线程,如当浏览器遇到link/script/img等请求后,就会开启该线程去加载资源文件。

二、浏览器请求HTML的过程

在这里插入图片描述

  1. 第一次访问:
    用户在浏览器中首次访问一个网址时,浏览器首先会将该网址发送到DNS服务器进行解析,解析完成后会返回浏览器一个ip地址,浏览器获取到该ip地址后,向服务器发送该ip地址请求,服务器收到请求后,读取该网页请求文件,发送到客户端浏览器,浏览器接收到服务器返回的HTML,进行显示。
    如果服务器硬盘中有该HTML,则直接返回,即我们常理解的静态网页;否则,通过后端引擎读写数据库,动态生成一个HTML,返回给浏览器。
  2. 第二次访问:
    用户在浏览器中第二次访问一个网址时
    1)浏览器首先获取资源中的header信息,查看是否命中强缓存(根据Cache-Control和Expires判断,其中Cache-Control的优先级要更高),如果命中强缓存,且缓存结果有效,则浏览器不与服务器进行交互,直接从缓存中读取资源;
    2)如果没有命中强缓存,则浏览器与服务器进行交互,查看是否命中协商缓存(根据Last-modified/If-Modified-Since和Etag/If-None-Match进行判断,其中Etag的优先级更高),如果命中协商缓存,则服务器返回一个新的响应头信息和304状态码,不返回资源,浏览器直接从缓存中读取资源;
    3)如果没有命中协商缓存,则服务器返回新的响应头信息和资源以及200状态码。

知识点补充,关于缓存标识(Response Headers):

缓存表示类型-协议特点
Expaires强缓存-http 1.0服务器返回该请求结果缓存的到期时间,要求服务器与客户端的时钟保持严格的同步,如果不同步,则强制缓存直接失效
Cache-Control强缓存-http 1.1使用max-age指定组件被缓存多久,从请求开始在max-age时间内浏览器使用缓存,之外的使用请求,以此消除Expires的限制
Last-Modified/If-modified-Since协商缓存-http 1.0返回该资源文件在服务器最后被修改的时间
Etag/If-none-Match协商缓存-http 1.1返回当前资源文件的一个唯一标识,通过比对该标识判断是否过期,相交于Last-Modified解决了:1.一些文件可能会周期性更改,但其中的内容并不改变;2.If-modified-Since的粒度是秒级的,而某些文件可能在秒以下的时间修改;3.某些服务器不能精确得到文件的修改时间

三、浏览器渲染HTML的过程

浏览器渲染页面的过程
在浏览器拿到资源文件后,浏览器就会在内存条中开辟出一块栈内存,用来给代码的执行提供环境,同时分配一个主线程,对拿到的HTML文件进行一行行的解析和执行代码。
我理解的这个主线程就是GUI渲染线程和js线程的结合,而这两个线程是互斥的,当一个线程在运行时,另一个线程就会挂起。
GUI渲染线程在解析文档时,当遇到link/src/img等外部资源文件请求时,就会开启异步http请求线程,去加载这些文件;当遇到JavaScript代码时,就会交给JS线程去处理,此时渲染线程挂起。通过头部link的方式引入的css的加载,是不会阻塞dom树的渲染,因为是在不同的线程。

  1. GUI渲染线程自上而下执行解析HTML文档,生成DOM树;
  2. 当CSS资源请求完成后,解析CSS文件(包含内联式和外部请求到的文件)生成CSSOM树,再结合DOM树和CSSOM树生成渲染树RenderObject树,用于渲染。
  3. Layout,即回流,负责对RenderObject树中的元素的尺寸、位置等计算;
  4. Painting,即重绘,负责绘制页面的像素信息;
  5. 渲染进程将默认的图层和复合图层交给GPU进程,GPU进程再将各个图层合成,最后显示出页面。

根据以上的特点,可以进行性能优化,如:
1.尽可能早的提前引入css文件,因为css文件的加载不会阻塞dom树的渲染;
2.css中引入的资源可以使用预加载,如link标签中的rel="preload"属性;
3.在dom和cssom渲染之后再加载js文件,因为GUI渲染线程和js线程是互斥的,执行js文件会阻塞渲染。
4.对资源进行合并压缩,如js、css、图片等文件。React项目通过webpack打包压缩后生成的bundle.js文件其实就是对资源的合并压缩,这样在请求js文件时就只需要发送一次http请求即可;
5.图片懒加载,即生成dom树时不加载图片,等到渲染树经过回流重绘,整个页面加载完成之后,再单独请求图片资源,如果区域有滚动条,则滚动到哪个区域再进行图片加载。
6.音视频走流文件。
7.因为每次操作dom都会导致浏览器的回流和重绘,而DOM元素实际是非常庞大的,因此可以通过减少对DOM的操作来进行性能优化。虚拟DOM的出现就是将DOM的对比放在js层,通过高效的diff算法计算,找到变更的DOM节点,更新真实DOM时只更新变更的部分,避免对整颗DOM树进行变更,从而提高渲染效率。

四、JS线程

渲染线程和js线程是互斥的,因为因为js代码在执行时可能会引发回流和重绘,即如果修改dom元素属性的同时进行渲染,那么渲染线程前后获得的元素数据可能会不一致。
JS线程在执行时,需要其他几个线程进行辅助。
在这里插入图片描述
执行js代码时,js线程作为主线程,执行同步任务,当碰到异步任务时,就交给事件触发线程,如果事件触发线程中包含onclick、ajax、setTimeout请求等就交给异步http请求线程执行,其中setTimeout的计时任务是由定时器线程完成。当这些异步任务执行完毕,就会将结果放入任务队列中,当js线程空闲时,就会执行任务队列中的任务。这整个过程是不停的循环的,这个机制就叫事件循环机制Event Loop。
JS线程中的任务分为同步任务和异步任务,而异步任务又包括微任务(micro task)和宏任务(macro task),微任务的优先级要高于宏任务。

  • 微任务:Promise,process.nextTick;
  • 宏任务:包括整体代码script,setTimeout,setInterval。
    在这里插入图片描述
    微任务和宏任务有着各自的任务队列(Event Queue),主线程优先读取微任务队列中的任务。

五、v8引擎简介

js线程的所有工作就是由js引擎完成的。Javascript本质上是一种解释型语言,与编译型语言不同的是它需要一边执行一边解析,而编译型语言在执行时就已经完成编译,执行速度会更快。因此V8引擎的主要目的就是为了提高Javascript的解析执行速度,V8使用C++开发。V8引擎的出现,为Virtual DOM的产生提供了大前提,因为Virtual DOM的本质是用JS模拟DOM结构,操作虚拟DOM,就是操作js对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值