浏览器渲染原理及性能优化

大家好,我是前端岚枫,两个多月没更新博客了,这段时间在忙着找工作,入职新公司,各项都有序的进行着,过年的一年算是很特殊的一年,经历7.20暴雨,8月疫情在家办公一个月,及后面的疫情,12月开始原公司长期放假,这些种种,真是一言难尽,但是进入2022年有个好的开始,1月入职新公司,年会抽奖中奖,紧接着没有被疫情留在郑州,顺利回家过年。新的一年开始,我的技术博文更新也会持续更新。今天主要跟大家分享我整理的浏览器渲染原理及性能优化:性能优化是我们工作中常遇到一些问题, 也是面试官经常提问的问题,希望下面文章对大家有所帮助。

一、进程与线程

  • 进程是操作系统资源分配的基本单位,进程中包含线程
  • 线程是由进程所管理的,为了提升浏览器的稳定性和安全性,浏览器采用了多进程模型
image.png
image.png
  • 浏览器进程:负责界面显示、用户交互、子进程管理、提供存储等
  • 渲染进程: 每个页面都有单独的渲染进程,核心用于渲染页面
  • 网络进程:主要处理网络资源加载(html、css、js 等)
  • GPU进程:3d绘制,提高性能
  • 插件进程:chrome中安装的一些插件

二、从输入URL到浏览器显示页面发生了什么

用户输入的关键字还是URL?如果是关键字则使用默认搜索引擎生成URL

  1. 用户输入url地址(关键字 会将关键字根据默认引擎生成地址)会开始导航,浏览器进程里面做
  2. 浏览器进程 :会准备一个渲染进程用户渲染页面
  3. 网络进程加载资源,最终将加载的资源交给渲染进程来处理
  4. 渲染完毕显示 ipc

网络七层模型

  • 先去查找缓存,检测缓存是否过期,直接返回缓存中的内容
  • 看域名是否被解析,DNS协议,将域名解析成ip地址(DNS基于UDP)ip+端口号 host
  • 请求是https SSL协商
  • ip地址来进行寻地址,排队等待,最多能发送6个http请求
  • tcp 创建链接,用于传输(三次握手)
  • 利用tcp传输数据(拆分成数据包 有序)可靠、有序,服务器按照顺序来接受
  • http 请求(请求行 请求头 请求体)
  • 默认不会断开keep-alive, 为了下次传输数据时候可以复用上次的创建的链接
  • 服务器收到数据后(响应行 响应头 响应体)
  • 服务器返回301 302 会进行重定向操作
  • 服务器返回304 去查询浏览器缓存进行返回

http 0.9 负责传输html 最早的时候没有请求头和响应头
http 1.0 提供了 http的header 根据header 的不同来处理不同的资源
http 1.1 默认开启了keep-alive 链接复用 管线化 服务器处理多个请求(队头阻塞问题)
http 2.0 用同一个tcp链接来发送数据 一个域名一个tcp(多路复用)头部压缩 服务器可以推送数据给服务端
http3.0 解决了tcp的队头阻塞问题 QUIC协议 采用了udp

渲染流程

image.png
image.png
  1. 浏览器无法直接使用HTML,需要将HTML转化成DOM树。(document)
  2. 浏览器无法解析纯文本的css样式,需要对css进行解析成styleSheets.(document.styleSheets)
  3. 计算出DOM树中的每个节点的具体样式
  4. 创建渲染(布局)树,将DOM树中可见节点,添加到布局树中,并计算节点渲染到页面的坐标位置,(layout)
  5. 通过布局树,进行分层(根据定位属性,transform属性,clip属性等)生产图层树
  6. 将不同图层进行绘制,转交给合成线程处理,最终生产页面,并显示到浏览器上(Painting Display)

查看layer并对图层进行绘制的列表

  • css 不会阻塞html解析, 先解析html,再解析css, 样式
  • css 放到底部,可能会导致重绘效果, 当html 渲染时候,会先扫描js 和css 渲染从上到下,边解析边渲染
  • 渲染DOM时,要等待样式加载完毕
  • js会阻塞html解析,阻止DOM渲染 需要暂停DOM解析去执行js ,js可能会操作样式,所以需要等待样式加载完成

所以js 一般放页面底部,css 放头部

总结:DOM 如何生成

  • 在解析前会先执行预解析操作,会预先加载js、css等文件
  • 字节流 =》分词器 =》Token =》根据token 生成节点 =》插入到DOM 树中
  • 遇到js 执行过程中遇到script 标签,HTMLParse会停止解析,(下载)执行对应的脚本
  • 在js 执行前,需要等待当前脚本之上的所有css 加载解析完毕(js是依赖css的加载)#

三、Perfomance API

image.png
image.png

image.png
image.png
// js
window.addEventListener('DOMContentLoaded', function(){
    let s = 0;
  for(let i = 0; i< 10000000; i++){
    s+=i;
  }
  setTimeout(()=>{
    document.body.appendChild(document.createtextNode('hello'))
  },1000)
})
setTimeout(()=>{
    const {
    fetchStart, //开始访问
    requestStart, //请求的开始
    responseStart, //响应的开始
    responseEnd, //响应的结束
    domInteractive, // dom 可交互的时间点
    domContentLoadedEventEnd, //dom加载完毕
    loadEventStart //所有资源加载完毕
  } = performance.timing;
  
  let TTFB = responseStart - requestStart; //首字节返回的事件 服务器处理能力
    let TTI = domInteractive - fetchStart; //整个的一个可交互的时间
  let DCL= domContentLoadedEventEnd - fetchStart; //DOM整个加载完毕
  console.log(TTFB, TTI, DCL) //如图一
  const paint = performance.getEnteriesByType('paint')
  console.log(paint[0].startTime); //FP

}, 3000)

//递归看load 的时间不能为0 mutationObserver
new PerformanceObserver((entryList)=>{
    console.log(entryList.getEntries)
}).observe({entryTypes:['element']})

图一


image.png
image.png

图二


image.png
image.png

四、网络优化策略

  1. 减少HTTP请求数,合并js、css,合理内嵌js、css
  2. 合理设置服务器端缓存,提高服务器处理速度。(强制缓存、协商缓存)
  3. 避免重定向,重定向会降低响应速度(301,302)
  4. 使用dns-prefetch,进行DNS预解析
  5. 采用域名分片技术,讲资源放到不同的域名下,同一个域名最多处理6个TCP链接问题
  6. 采用CDN加速加快访问速度。(指派最近、高度可用)
  7. gzip压缩优化,对传输资源进行体积压缩(html,css,js)
Content-Encoding:gzip
  1. 加载数据优先级:preload(预先请求当前页面需要的资源) prefetch(将来页面中使用的资源),将数据缓存到HTTP缓存中
<link rel="preload" href="style.css" as="style">

五、关键渲染路径

image.png
image.png
  • 重排(回流)Reflow:添加元素、删除元素、修改大小、移动元素位置、获取位置等相关信息都会引起重排。
  • 重绘 Repaint: 页面中元素样式的改变并不影响它在文档中的位置。

1.强制同步布局问题

JavaScript强制将计算样式和布局操作提前到当前任务中

<div id="app"></div>
<script>
  function reflow(){
    let el = documnet.getElementById('app');
    let node = doucument.createElement('h1');
    node.innerHTML = 'hello';
    el.appendChild(node);
    //获取位置会导致重排(重新布局)
    console.log(app.offsetHeight);
    
  }
  window.addEventListener('load',function(){
    for(let i=0; i<100; i++){
        reflow()
    }
  })
  
</scpript>

减少回流和重绘

  1. 脱离文档流
  2. 渲染时给图片增加固定宽高
  3. 尽量使用css3动画
  4. 可以使用will-change提取到单独的图层中

六、静态文件优化

1. 图片优化

图片格式:

  • jpg:适合色彩丰富的照片、banner图;不适合图形文字、图标(纹理有锯齿),不支持透明
  • png: 适合纯色、透明、图标、支持半透明;不适合色彩丰富图片,因为无损储存会导致储存体积大
  • gif: 适合动画,可以动的图标;不支持半透明,不适合存储彩色图片
  • webp: 适合半透明图片,可以保证图片质量和较小的体积
  • svg: 相比于jpg和png,它的体积更小,渲染成本过高,适合小且色彩单一的图标

图片优化:

  • 避免空src的图片
  • 减小图片尺寸,节约用户流量
  • img标签设置alt属性,提升图片加载失败时的用户体验
  • 原生的loading:lazy图片懒加载
<img loading="lazy" src="./images/1.jpg" widht="300" height="450" />
  • 不同环境下,加载不同尺寸和像素的图片
  • 对于较大的图片可以考虑采用渐进式图片
  • 采用base64URL 减少图片请求
  • 采用雪碧图片合并图标图片

2. HTML优化

  1. 语义化HTML:代码简洁清晰,利于搜索引擎,便于团队开发维护
  2. 提前声明字符编码,让浏览器快速确定如何渲染网页内容
  3. 减少HTML嵌套关系,减少DOM节点数量
  4. 删除多余空格,空行、注释、及无用的属性等
  5. 避免table布局

3. css 优化

  1. 减少伪类选择器,减少样式层数,减少使用通配符
  2. 避免使用css表达式,css表达式会频繁求值,当滚动页面,或者移动鼠标时,都会重新计算(IE6,7)
background-color:expression(new Date()).getHours()%2 ? "red" : "yellow");
  1. 删除空行、注释、减少无意义的单位、css进行压缩
  2. 使用外链css,可以对css进行缓存
  3. 添加媒体字段,只加载有效的css 文件
<link href="index.css" rel="stylesheet" media="screen and(min-width:1024px)"
  1. css contain属性将元素进行隔离
  2. 减少@import使用,由于import采用的串行加载

4. js 优化

  1. 通过async 、defer异步加载文件
image.png
image.png
  1. 减少DOM操作,缓存访问过的元素
  2. 操作不直接应用到DOM上,而应用到虚拟DOM上。最后一次性的应用到DOM上
  3. 使用webworker解决程序阻塞问题
  4. IntersectionOberver
const observer = new IntersectionOberver(function(changes){
    changes.forEach(function(element, index){
      if(element,intersectionRatio > 0){
      observer.unobserve(element.target);
        element.target.src = element.target,dataset.src;
      }
    });
  });
function initObserve(){
    const listItems = document.querySelectAll('img');
  listItems.forEach(function(item){
  observer.observe(item)
  })
}
initObserver

  1. 虚拟滚动 vertual-scroll-list
  2. requestAnimationFrame、requestIdleCallback
image.png
image.png
  1. 尽量避免使用eval,消耗时间久
  2. 使用事件委托,减少事件绑定个数
  3. 尽量使用canvas动画、css动画

七、优化策略

  • 关键资源个数越多,,首次页面加载时间就会越长
  • 关键资源的大小,内容越小,下载时间越短
  • 优化白屏:内联css和内联js,移除文件下载较小文件体积
  • 预渲染,打包时候进行预渲染
  • 使用SSR加速首屏加载(耗费服务端资源),有利于SEO优化,首屏利用服务器端渲染,后续交互采用客户端渲染

八、浏览器的存储

  • cookie: cookie过期时间内一直有效,存储大小4k左右、同时限制字段个数,不适合大量的数据存储,每次请求会携带cookie,主要可以利用做身份检查验证

    设置cookie有效期;根据不同子域划分cookie较少传输;静态资源域名和cookie域名采用不同域名,避免静态资源访问时携带cookie

  • localStroage: chrome下最大存储5M,除非手动清除,否则一直存在,利用localStorage存储静态资源

function cacheFile(url){
let fileContent = localStorage.getItem()
if(file){
  eval(fileContent)
} else {
  let xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onload = function(){
    let responseText = xhr.responseText;
    eval(responseText);
    localStorage.setItem(url,responseText)
  }
  xhr.send()
}
}
cacheFile('/index.js')
  • sessionStorage: 会话级别存储,可用于页面间的传值
  • indexDB:浏览器的本地数据库(基本无上限)

九、增加体验 PWA(Progerssive Web App)

webapp用户体验差(不能离线访问),用户粘性低(无法保存入口),pwa就是为了解决这一系列问题让webapp具有快速,可靠,安全等特点

  • Web App Mainfset: 将网站添加到桌面、更类似native的体验
  • Service Worker: 离线缓存内容,配合cache API
  • Push Api & Notification Api: 消息推送与提醒
  • App Shell & App Skeleton App壳、骨架屏
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容