小宋爱睡觉 小宋爱睡觉
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
  • CDN
  • 其他优化手段
    • 如何根据chrome的timing优化
    • 懒加载
    • 懒加载和预加载的区别
    • link标签的预处理
    • 介绍一下什么是回流和重绘
    • 如何避免回流和重绘
    • 如何优化动画
    • documentFragment是什么?用它跟直接操作dom有什么区别
    • 介绍一下防抖和节流
    • 图片优化
    • 移动端优化
    • 面试回答性能优化怎么显得有条理
  • Webpack优化
  • 性能优化
Crucials
2021-12-16

其他优化手段

# 如何根据chrome的timing优化重要

性能优化API

  • Performance。performance.now()与new Date()区别,它是高精度的,且是相对时间,相对于页面加载的那一刻。但是不一定适合单页面场景
  • window.addEventListener("load", ""); window.addEventListener("domContentLoaded", "");
  • Img的onload事件,监听首屏内的图片是否加载完成,判断首屏事件
  • RequestAnmationFrame 和 RequestIdleCallback
  • IntersectionObserver、MutationObserver,PostMessage
  • Web Worker,耗时任务放在里面执行

检测工具

  • Chrome Dev Tools
  • Page Speed
  • Jspref

window.onload = function(){
  setTimeout(function(){
    let t = performance.timing
    console.log('DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart).toFixed(0))
    console.log('TCP链接耗时 :' + (t.connectEnd - t.connectStart).toFixed(0))
    console.log('request请求耗时 :' + (t.responseEnd - t.responseStart).toFixed(0))
    console.log('解析dom树耗时 :' + (t.domComplete - t.domInteractive).toFixed(0))
    console.log('白屏时间 :' + (t.responseStart - t.navigationStart).toFixed(0))
    console.log('domready时间 :' + (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0))
    console.log('onload时间 :' + (t.loadEventEnd - t.navigationStart).toFixed(0))

    if(t = performance.memory){
      console.log('js内存使用占比 :' + (t.usedJSHeapSize / t.totalJSHeapSize * 100).toFixed(2) + '%')
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 懒加载

概念:

懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能

如果使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面列表较长(长列表)的场景中。

特点:

  • 减少无用资源的加载,减少服务器的压力和流量

  • 提升用户体验,减少用户等待时间

  • 防止加载过多图片而影响其他资源文件的加载

实现原理:

图片的加载是由 src引起的,当对src 赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5 的 data-xxx属性来储存图片的路径,在需要加载图片的时候,将data-xxx中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。

注意:data-xxx 中的 xxx 可以自定义,这里我们使用 data-src 来定义。

懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。

使用原生JavaScript实现懒加载:

知识点:

(1)window.innerHeight 是浏览器可视区的高度

(2)document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动的过的距离

(3)imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离)

(4)图片加载条件:img.offsetTop < window.innerHeight + document.body.scrollTop

img

<div class="container">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
		var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
		var winHeight= window.innerHeight;
		for(var i = 0; i < imgs.length; i++){
			if(imgs[i].offsetTop < scrollTop + winHeight){
				imgs[i].src = imgs[i].getAttribute('data-src');
			}
		}
	}
  window.onscroll = lozyLoad();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 懒加载和预加载的区别

这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

  • 懒加载也叫延迟加载,指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。
  • 预加载指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。 通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 src 属性,来实现图片的预加载。

# link标签的预处理重要

dns-prefetch。当 link 标签的 rel 属性值为“dns-prefetch”时,浏览器会对某个域名预先进行 DNS 解析并缓存。这样,当浏览器在请求同域名资源的时候,能省去从域名查询 IP 的过程,从而减少时间损耗。下图是淘宝网设置的 DNS 预解析

  • preconnect。让浏览器在一个 HTTP 请求正式发给服务器前预先执行一些操作,这包括DNS 解析、TLS 协商、TCP 握手,通过消除往返延迟来为用户节省时间
  • prefetch/preload。两个值都是让浏览器预先下载并缓存某个资源,但不同的是,prefetch 可能会在浏览器忙时被忽略,而 preload 则是一定会被预先下载。
  • prerender。浏览器不仅会加载资源,还会解析执行页面,进行预渲染

# 介绍一下什么是回流和重绘特别重要

回流

当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就称为回流。

下面这些操作会导致回流:

  • 页面的首次渲染

  • 浏览器的窗口大小发生变化

  • 元素的内容发生变化

  • 元素的尺寸或者位置发生变化

  • 元素的字体大小发生变化

  • 激活CSS伪类

  • 查询某些属性或者调用某些方法

  • 添加或者删除可见的DOM元素

在触发回流(重排)的时候,由于浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致周围的DOM元素重新排列,它的影响范围有两种:

  • 全局范围:从根节点开始,对整个渲染树进行重新布局
  • 局部范围:对渲染树的某部分或者一个渲染对象进行重新布局

重绘

当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,这个过程就是重绘。

下面这些操作会导致回流:

  • color、background 相关属性:background-color、background-image 等

  • outline 相关属性:outline-color、outline-width 、text-decoration

  • border-radius、visibility、box-shadow

注意: 当触发回流时,一定会触发重绘,但是重绘不一定会引发回流。

什么是流式布局

页面元素的宽度按照屏幕分辨率进行适配调整,但整体布局不变。通常宽度是以%来表示,但是设置了最大宽度max-width和最小宽度min-width,分辨率发生变化的话元素大小会变,但是整体布局不变,缺点很明显是屏幕尺寸跨度大不能正常显示出来(页面元素被拉得很长,但是高度和文字大小不变)

# 如何避免回流和重绘重要

减少回流与重绘的措施:

  • 操作DOM时,尽量在低层级的DOM节点进行操作

  • 不要使用 table 布局, 一个小的改动可能会使整个 table 进行重新布局

  • 使用CSS的表达式

  • 不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式。

  • 使用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素

  • 避免频繁操作DOM,可以创建一个文档片段 documentFragment ,在它上面应用所有DOM操作,最后再把它添加到文档中

  • 将元素先设置 display: none ,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。

  • 将DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制。

浏览器针对页面的回流与重绘,进行了自身的优化——渲染队列

浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。

上面,将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次回流,变成了只触发一次回流。

# 如何优化动画

对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作DOM,就就会导致页面的性能问题,我们可以将动画的 position 属性设置为 absolute 或者 fixed ,将动画脱离文档流,这样他的回流就不会影响到页面了。

# documentFragment是什么?用它跟直接操作dom有什么区别重要

概念

DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

MDN (opens new window)

当我们把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,他只是相当于一个占位符,而是它的所有子孙节点。在频繁的DOM操作时,我们就可以将DOM元素插入DocumentFragment,之后一次性的将所有的子孙节点插入文档中。和直接操作DOM相比,将DocumentFragment 节点插入DOM树时,不会引起DOM树的重新渲染(reflow),从而减少回流(一次append只回流一次)

# 介绍一下防抖和节流重要

  • 函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。
  • 函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率

防抖函数的应用场景:

  • 按钮提交场景:防⽌多次提交按钮,只执⾏最后提交的⼀次

  • 服务端验证场景:表单验证需要服务端配合,只执⾏⼀段连续的输⼊事件的最后⼀次,还有搜索联想词功能类似⽣存环境请⽤lodash.debounce

节流函数的适⽤场景:

  • 拖拽场景:固定时间内只执⾏⼀次,防⽌超⾼频次触发位置变动

  • 缩放场景:监控浏览器resize

  • 动画场景:避免短时间内多次触发动画引起性能问题

# 图片优化

  1. 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。

  2. 对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。

  3. 小图使用 base64 格式

  4. 将多个图标文件整合到一张图片中(雪碧图)

  5. 选择正确的图片格式:

    • 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
    • 小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替
    • 照片使用 JPEG

# 移动端优化

# 面试回答性能优化怎么显得有条理

分点作答

让文件加载更快

  • 让传输的数据包更小(压缩文件/图片):图片压缩和文件压缩
  • 减少网络请求的次数:雪碧图/精灵图、节流防抖
  • 减少渲染的次数:缓存(HTTP缓存、本地缓存、Vue的keep-alive缓存等)

让文件渲染更快

  • 提前渲染:ssr服务器端渲染
  • 避免渲染阻塞:CSS放在HTML的head中 JS放在HTML的body底部
  • 避免无用渲染:懒加载
  • 减少渲染次数:对dom查询进行缓存、将dom操作合并、使用减少重排的标签

或者可以这样

其实可以参照那道输入url到显示全过程的问题

  1. DNS的预解析(dns-prefetch)(尽量放在网页的前面)
  2. 缓存可以避免重复加载资源 etc不变的资源用强缓存(expires, cache-control:max-age)... 顺序cc>expire
    • 后面唠唠协商缓存Last-Modified IF-Modified-Since Etag IF-None-Match

这里要注意一下

大多数候选人都只答概念,我们可以从什么文件出发谈一下选型

  • 对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存
  • 对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
  • 对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件
  1. 讲完缓存可以HTTP2的多路复用,让多个请求复用同一个TCP连接,还有2.0的头信息压缩

  2. 预加载:preload 可以对当前页面所需的脚本、样式等资源进行预加载

  3. 预加载:有些资源不需要马上用到,但是希望尽早获取,降低首屏加载时间

    <!-- 强制浏览器请求资源,并且不会阻塞 onload 事件 -->
    <link rel="preload" href="http://example.com">
    
    1
    2

    这里可以顺便提一嘴

    可以在当前页加载下一页的资源,提升速度

  4. 预渲染:将下载的文件预先在后台渲染,可以使用以下代码开启预渲染

    <!-- 虽然可以提高页面的加载速度,但是要确保该页面百分百会被用户在之后打开,否则就白白浪费资源去渲染 -->
    <link rel="prerender" href="http://crucials.com">
    
    1
    2
  5. 图片懒加载(监听scroll、图片data-src)

  6. 图片加载

    1. cdn加载
    2. 小图用base64
    3. 多图标用雪碧图
    4. 支持webp的浏览器用webp
    5. 用svg代替png
    6. 照片用jpeg
  7. 其他文件优化

    1. css放head
    2. 服务端开启gzip
    3. script的defer和async
    4. 使用webworker另开线程执行脚本不阻塞渲染
    5. 静态资源用cdn加载,避免cdn的域名和主站相同致携带cookies
  8. 运行时优化

    1. content方面:减少http请求,css精灵图减少dns查询
    2. css选择器...(尽量不嵌套.. css3开启GPU,使用link代替@import)
    3. 重排重绘...
    4. 动画优化(使用requestAnimationFrame代替setTimeout)
  9. webpack优化

    1. webpack4+ 打包自动开启代码压缩
    2. 使用es6模块开启tree shaking
    3. 路由拆分代码,按需加载
    4. 打包的文件添加hash配合ETag
  10. 监控(待完善)

    对于代码运行错误,通常的办法是使用 window.onerror 拦截报错。该方法能拦截到大部分的详细报错信息,但是也有例外

    • 对于跨域的代码运行错误会显示 Script error. 对于这种情况我们需要给 script 标签添加 crossorigin 属性
    • 对于某些浏览器可能不会显示调用栈信息,这种情况可以通过 arguments.callee.caller 来做栈递归
    • 对于异步代码来说,可以使用 catch 的方式捕获错误。比如 Promise 可以直接使用 catch 函数,async await 可以使用 try catch
    • 但是要注意线上运行的代码都是压缩过的,需要在打包时生成 sourceMap 文件便于 debug。
    • 对于捕获的错误需要上传给服务器,通常可以通过 img 标签的 src发起一个请求⬇️
上次更新: 2022/03/14, 11:48:12
CDN
Webpack优化

← CDN Webpack优化→

Copyright © 2021-2025 粤ICP备2021165371号
  • 跟随系统
  • 浅色模式
  • 深色模式