web前端性能优化

122 阅读4分钟

《一》前端页面的生命周期

多进程浏览器

  1. 浏览器主进程
  2. GPU进程
  3. 插件进程
  4. 网络进程
  5. 渲染进程:js引擎线程,事件触发线程,定时触发器线程,异步Http线程

1.DNS解析

将url上的host转换为ip地址

浏览器缓存-系统自身dns缓存-系统hosts文件查找-本地域名服务器-根域名服务器/COM顶级域名服务器/权限域名服务器-找不到报错

原理和优化

DNS解析拿到ip地址,建立网络连接【此时数据链路层和网络层打通,需要通过传输层建立端到端的连接,发起http请求,即需要tcp协议的“三次握手”和“四次挥手”】

WechatIMG196.jpeg

2.前后端交互

反向代理服务器,如nginx

  1. 负载均衡
  2. 安全防火墙
  3. 加密和ssl加速
  4. 数据压缩
  5. 跨域
  6. 静态资源缓存 其他优化空间:

http协议

  • http1.0 短连接
  • http1.1 长连接,connection:keep-alive,服务器配置持续化时间,优化:雪碧图
  • http2.0 多复用特性,http头部压缩,设置请求优先级,服务器主动推送 浏览器缓存
  • 强缓存:cache-control:max-age 200
  • 协商缓存:if-none-match和服务端的e-tag是否匹配,比http1.0的last-modified更准确。304

3.经历网络请求过程,从服务器获取到的页面文件,将其渲染出来

《二》资源压缩和合适的文件格式选型

矢量图:svg,放大不失真 位图:jpg,png,gif,jpeg

  • jpeg:使用glup将images进行渐进式编程
  • gif:内容长的用video代替
  • png:npm引入插件,对多余块进行删除压缩
  • webp:用window.navigater.userAgent处理兼容性问题
  • img的srcset和picture

《三》加载优化

图片,视频加载

传统懒加载

  • class,src,data-src属性
  • 利用事件监听scrool,resize回调事件
  • 判断图片是否在视窗內img.getBoundClientReact.top < window,innerHeight
  • 请求赋值
  • 图片加载完,取消监控 优化:节流200ms但重复调用setTimeout,200ms时间不精准等依旧存在性能问题。 代码:p54

intersection onserver方式

intersection onserver:每当页面滚动,target与数据交集时,会触发intersection onserver回调函数。 存在兼容性问题,polyfill插件

css类名方式 css的background-image .one.visible高清 .one低清

entry.target.classList.add('visible')

chrome 75自带的loading=“lazy”

if('loading' in HTMLImageElement.prototype){
    // loading=“lazy”
}else{
    // 传统方式
}

视频加载

video preload 请求连接数6,preload=none/metadate

注意事项

  • 要设置缓存区,提前加载,如intersection onserver方式中的rootMargin
  • 资源占位:不用导致位移,回流
  • 图片加载失败,用image.onerror回调重新加载

资源优先级

预加载

link ref="preload" as="style" 对单个文件进行预加载,快也有缓存。缺点:在浏览器和服务器中发生额外的往返请求。解决办法:http2推送

预连接

link ref="preconnect" link ref="dns-prefetch"

预提取

link ref="prefetch"

《四》书写高性能代码

条件语句

  • 1,2条用if else
  • 2-10条用switch
  • 超过10条,借助策略模式,用数组索引或对象属性方式查找 循环语句:
  • for-in
for(let props in array){
    if(object.hasOwnProperty(props)){}
}

可遍历json课枚举属性,但要检测原型,性能比较慢

  • foreach 比较直观,也慢
  • for-of es6新加的,相对比较快,但没有常规循环快
  • 三种常规循环:for/while/do-while 递归

缺失或不明确递归的终止条件会造成卡顿。,通过空间换时间,有内存开销。由于浏览器有限制调用栈大小,超出限制的递归无效。可改成迭代的方式,性能慢点,不过不在限制于浏览器对js调用栈的限制。 优化:利用闭包避免重复操作,存在问题:函数闭包延长了局部变量的存活率,数据量大又不能回收,会存在内存溢出。

字符串处理

《五》构建优化

css和js的压缩合并

合并: 优点:减少网络丢包严重现象

缺点:

  • 合并文件大,加载完在渲染,首次渲染慢
  • 存在缓存失效问题【md5戳,标识发生改变更新】 建议:

合并公共库,改动不频繁

webpack优化【不太全】

  • webpack采用局部安装+npx

  • loader上配置exclude,如排除node-modules,减少loader的执行,可配置缓存:loader:“babel-loader?cacheDirectory=true”

  • 配置压缩插件,resolve中alias参数

  • 使用dllplugin拆分配置第三方包,如react,react-dom,lodash等。存在就获取,不存在就在node-modules中获取所需模块

《六》渲染优化

实现动画效果

css:transition/animation html:canvas js:setTimeout

  • 因为setTimeout事件执行机制,需要等待主线程执行完,会比延迟时间晚些,与屏幕刷新时间不同步,出现丢帧卡顿现象
  • 用requestAnimataionFrame:将回调函数的执行时间由系统决定,与屏幕刷新时间同步

恰当的使用web worker

节流与防抖(代码p124)

以闭包的形式包裹回调函数,通过自由变量缓存计时器信息,最后用setTimeout控制事件触发的频率来实现

节流:第一次触发,如scrool事件,懒加载

return(params)->{
    if(now-last>=time){
        claaback(params)
    }
}

防抖:最后一件事件【需要设置一条延迟等待的时间地线】

return(params)->{
// 判断事件触发时间是否超出节流时间间隔
    if(now-last<time){
        clearIimeout(timer)
        timer = setTimeout(()=>{
            last=now;
            claaback(params)
        })
    }
}

css计算样式优化

  • 用标签选择器替代通配符 css选择器匹配从右到走,如.list li{},是先匹配全部li,在找对应的 .list 。我们需要在li设置为 .litag,减少查找标签元素的范围,少用通配符。
  • 降低选择器的复杂性 如设置class类名
  • 使用BEM规范 建议使用单一的类选择器,不仅结构清晰,而且渲染阶段的样式计算性能提升

页面布局

页面布局:js执行-样式计算-页面布局-绘制-合成

  • 使用类名对样式合并修改

  • 缓存对敏感属性的计算let top=list.offsetTop;

  • 使用requestAnimationFrame控制渲染帧

  • will-change / transform:translate(0)

控制面板 profiler精准优化