前端性能优化总结

先说总结,前端优化核心逻辑就是:
减少请求数(或同时间请求数)与请求资源大小,减少重绘与回流


减少请求数(或者同一时间请求数)与请求资源大小

  1. 文件压缩与合并
    html css js文件压缩合并打包,比如gzip压缩,js混淆等(目前多通过webpack构建处理),压缩打包后减少了资源大小与请求数量

  2. 图片压缩

  • 雪碧图(又称精灵图):多张小图片合成一张大图减少请求数
  • 项目图片无损压缩后再使用, 这里推荐一个压缩工具https://tinypng.com/
  • 小图片base64化:一些小图片(一般不超过5k),可以通过转成base64的方式直接打入资源包,这样就减少了请求数,目前流行的方案是通过webpackurl-loaderloader配置处理,不过图片转成base64会提高33%大小(原理是把图片每3个字节转成了4个字节),所以不能转太大的图片,会造成资源包过大。
  1. 加载优化(加载优化并不减少请求数,主要是利用一些技巧提升用户体验)
    服务端ssr首屏渲染: 多用于优化移动端应用用户体验,提高首屏加载速度。一些应用不想首页显示后ajax获取相关数据造成的闪动或loading,通过服务端渲染ssr的方式解决首屏加载问题,缺点对服务端压力大(ssr能讲的特别多,不展开了,感兴趣可以自己了解)
    预加载: 资源提前请求,需要是从缓存中加载。常见于H5活动页H5小游戏,为了保证整体页面的流畅度,预判用户行为预先加载资源(例如guagame那样加载所有图片资源后开始游戏)
    懒加载: 按需加载也称延迟加载,用于减少无效资源的加载。常见两种实现:

    1. 代理加载:方法是图片加载时先使用默认loading图占位,实际图片加载后替换,这样就可以更快显示整体页面布局,提高用户体验
    2. 按需加载(目前主要有2种应用实现)
      • 监听滚动条事件,当资源(主要是图片)即将进入视图区域时再加载显示,核心就是监听滚动高度scrollTop与元素高度clientHeight的比较
      • 监听用户交互事件(比如点击),一些封装组件,只有当用户使用相关功能的时候加载,核心逻辑就是响应事件后动态创建script标签加载资源(目前主流也是通过webpack配置() => import(**/**.js)这样的语法实现),最典型的场景就是路由跳转
  2. 缓存优化(核心还是尽量复用本地资源,减少请求数,减少请求资源大小)

    1. 使用CDN:CDN作为静态资源文件的分发网络(名词解释就是它能够能够实时地根据网络流量和各节点连接、负载状况以及到用户的距离和响应时间等综合信息将用户请求重新导向离用户最近的服务节点上,以达到用户就近取得所需的目的)能加快网站的资源加载速度,有效利用缓存的静态资源,下面说几个关于cdn的扩展问题:

      • cdn缓存导致用户拿不到最新文件:通用解决办法还是通过webpack打包将文件名hash处理,通过文件名变动让cdn缓存失效,每次版本更新,webpack会分析变动,只改变文件有变动的文件名,最大化的利用缓存,还要提醒一点,作为主入口的index.html是不缓存的,因为现代前端工程里面,index.html都是模板文件非常小,不需要缓存,以防止主入口更新失效,而模板里面的引入的资源文件路径都是根据hash动态生成,根据文件变动可以及时更新
      • 域名发散:http1协议一个网络链接,后一个网络请求必须等前一个请求结束才能使用,而目前主流的游览器都对同一域名下的最大网络链接数有限制,比如chrome是6,如果页面里图片等加载资源过多,加载逻辑就变成了串行的加载,影响效率,所以将静态资源放置在多个子域名下面绕过这个限制,最大化利用游览器并行加载。(http2没有这个问题,因为http2协议使用一种信道复用的技术,允许同一个网络链接可以并行的发送请求,前面的请求不完成并不会堵塞后面的请求)
    2. cookie优化:因为cookie一直在游览器与服务器中间传递,所以cookie优化的核心就是减少cookie大小,

      • 去除没必要的cookie
      • 设置合适的cookie过期时间(通过max-age字段)
      • 静态资源cdn的域名和主站的域名要分开,一些js,css,图片资源请求携带cookie是多余的,所以请求这些资源不需要发送cookie(可通过domain字段设置)
    3. HTTP缓存(主要介绍关于资源缓存有效时间和资源文件识别相关的字段):
      Pragma:可设置no-cache禁用缓存,兼容性最好,优先级高于Cache-Control,最高优先级
      Expires: 设置过期时间,优先级低于PragmaCache-Control,此时间是服务器时间,如果和本地时间不统一会导致问题
      Cache-Control: 解决Expires服务器时间与本地时间统一问题,优先级高于Expires,此字段请求和响应都可以设置(属性很多,说些关键的,感兴趣可以自行深入了解)

      • no-cache 不缓存
      • max-age=delta-seconds 服务端(响应情况)设置最大有效时间delta-seconds(有效时间内游览器直接缓存拿数据,不请求) 客户端(请求情况)就是告知服务端希望接受一个存在时间不超过``delta-seconds`秒的资源
      • s-maxage=delta-seconds 同max-age,区别是这个delta-seconds是设置的代理服务器时间
      • only-if-cached 代理服务器如果有资源不需要去服务器请求
      • must-revalidate 资源一定是从服务器获取,而非代理服务器缓存,如果失败返回504
      • last-modified与if-modified-since: 服务器通过last-modified字段告知客户端资源修改最后时间,游览器储存后通过if-modified-since字段发送储存时间,服务端收到请求后判断接收到的时间是否与当前一致,如果一致返回304,不返回资源,如果不一致,返回200,更新新的缓存时间并返回新的资源
      • eTag :效果等同于last-modified,有时候文件时间修改了,但是文件内容没有变化,这就导致last-modified不准确,所以通过文件hash值确定文件变化,是一种更准备的缓存策略
// Cache-Control可以多段设置 
Cache-Control: max-age=3600, must-revalidate  // 表示一定从原服务器获取资源,获取后1小时内无需再次请求走缓存
/* 
总结:
一个请求,可能有三种状态:
1. 本地有资源,也没有过期 这时候返回就是 200(from cache),直接走本地资源 最快(Cache-Control)
2. 本地有资源,但是过期了,去服务端请求,服务端判断文件没变化,返回304,不更新文件资源,还是走本地资源,一个简单的网络请求,也很快(last-modified与eTag字段)
3. 本地有资源(或者没资源),服务端判断文件有变化或者第一次请求,返回200,并发送文件资源,网络请求加资源下载,最慢 
*/

减少重绘与回流

回流(reflow): 触发页面重布局的行为(消耗很大),比如盒模型相关属性改变,定位与浮动,节点内容改变等,当页面布局和几何属性变化就需要回流
重绘(repaint): 不改变文档流布局,只改变样式(消耗小)的行为,比如字体颜色与背景相关属性,visibility等,只影响外观风格不影响布局就是重绘

频繁触发重绘与回流,会导致ui频繁渲染,最终阻塞js线程,导致js变慢,而这一方面的优化,更多是代码习惯的优化,大概讲几个通用的吧

  • 尽量减少会引起回流的操作,限制回流在一个图层中(图层, 可以类比ps的图层,简单说,就是脱离主文档流,比如一个元素设置了z-index或者transform: translateZ(0)属性它就是一个新的图层,如果一个dom元素频繁操作,应该独立成一个单独的图层,重绘回流操作就只限制在这一个图层,不要设置过多图层,图层合并计算是非常耗费资源的,所以只有当特别频繁的操作,例如动画,gif图才考虑独立图层出来)
  • css资源放在head里面(css link引入方式会阻塞页面渲染,将css放在head里面,加载完成后再渲染,防止页面闪动)
  • 使用translate替代top操作(top会触发回流,但是translate不会)
  • 使用opacity替代visibility(只考虑可见性的话visibility会触发重绘,但opacity不会,要考虑需求差异,opacity和visibility对点击事件的结果不一样)
  • 不要一条条改变dom样式,而是封装成预先定义的className整体替换(每次修改都会触发回流或重绘,整体替换只有一次)
  • 复杂的操作先将dom结构display:none 然后操作后显示(先把dom设置none,然后修改几十次后显示,也只触发2次回流)
  • 除非确实需要真实值,不然不要在循环中去获取dom的offsetHeight offsetWidth等属性,而是循环前就获取储存到变量中(因为这些属性的每一次读取都会触发一次回流)
  • 避免使用table布局(如果是div布局,修改dom,回流只会在这个dom后面的所有元素发生,但是table布局即使修改了最后一行一列也会导致整个table的重新布局)
  • 使用GPU硬件加速(当一个元素设置css属性transform: translateZ(0)或translate3d(0,0,0)的时候,游览器就默认启动)
  • 动画效果使用requestAnimationFrame代替setInterval操作(requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧随刷新频率,不因间隔时间过短造成过度绘制,也不会太长导致不流畅,且游览器有特别优化,更节省系统资源,提高性能)

其他优化

Web Worker: 本质就是可以创建一个新的线程,把非常耗费性能的操作放在worker线程里运行,不堵塞主线程,要考虑兼容问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容