• 【前端必备】七、页面性能优化


    1.文件优化

    图片优化

    • 一些修饰类图片可用CSS代替
    • 将多个图标文件整合到一张图片中 (CSS Sprite)
    • 选择正确的图片格式:
      • gif无损压缩,适合logo、线条等小型简单图像
      • jpeg适合照片、渐变图像
      • PNG-8相对于GIF来讲有对alpha透明通道的支持,PNG-24会比JPEG,GIF,PNG-8占用更多的存储空间
      • svg适合简单的平面矢量形状,复杂的渲染时需要较多计算。
    • 计算图片大小
       对于一张 100 _ 100 像素的图片来说,图像上有 10000 个像素点,如果每个像素的值是 RGBA 存储的话,那么也就是说每个像素有 4 个通道,每个通道 1 个字节(8 位 = 1 个字节),所以该图片大小大概为 39KB(10000 _ 1 * 4 / 1024)。

    其他文件优化

    • 静态资源使用 CDN加载
    • 重要的CSS文件放head中,其他可以放底部或动态加载
    • 将耗时的js代码使用Web Workers执行
    • <script>标签
      • 放在底部,避免阻塞渲染
      • 动态脚本加载,向DOM中插入<script>标签
      • 给标签加上 defer或async
        • defer ,表示该文件会并行下载,但是会放到 HTML 解析完成后顺序执行。
        • 没有任何依赖的JS文件可以加上async,表示加载和渲染后续文档元素的过程将和 JS 文件的加载与执行并行无序进行。

    2.懒执行、懒加载、预加载、预渲染、DNS预解析

    懒执行 将某些逻辑延迟到使用时再计算,可用于首屏优化 定时器,事件触发
    懒加载 将不关键的资源延后加载。 定时器,事件触发,可视区
    预加载 < link rel="preload" href="http://example.com" />  动态加载,Ajax
    预渲染 < link rel="prerender" href="//yuchengkai.cn" />  
    DNS预解析 < link rel="dns-prefetch" href="//yuchengkai.cn" />  
    服务器渲染

    打开或关闭DNS预解析:

    • 在服务器端发送 X-DNS-Prefetch-Control 报头
    • 在文档中使用meta标签:<meta http-equiv="x-dns-prefetch-control" content="on">
      在一些高级浏览器中,页面中所有的超链接,默认打开了DNS预解析。
      但是,如果页面中采用的https协议,很多浏览器是默认关闭了超链接的DNS预解析。
      如果加了上面这行代码,则表明强制打开浏览器的预解析。

    3.强缓存与协商缓存

    强缓存

    表示在缓存期间不需要请求,state code 为 200。
    两种响应头实现: ExpiresCache-Control
    Expires: Wed, 22 Oct 2018 08:41:00 GMT 在指定的绝对时间后过期
    Cache-control: max-age=3030秒后过期
    Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires

    协商缓存

    向服务器确认缓存是否过期,配合强缓存,两种实现方式。ETag 优先级比 Last-Modified 高。
    (1)校验修改时间: Last-ModifiedIf-Modified-Since
    (2)校验文件指纹: ETagIf-None-Match

    首次请求资源,响应头上会有Last-Modified或ETag。
    再次请求时,请求头上带着If-Modified-Since、If-None-Match。
    服务器进行校验,如果资源没变,响应304 Not Modifield,
            改变了,则返回资源带上新的Last-Modified或ETag。

    如果在本地打开缓存文件,就会造成 Last-Modified 被修改,所以在 HTTP / 1.1 出现了 ETag 。

    浏览器行为对缓存的影响

    1)当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;
    2)当f5刷新网页时,跳过强缓存,但是会检查协商缓存;

    Cache-Control消息头字段

    在http 请求和响应中通过指定指令来实现缓存机制。缓存指令是单向的, 这意味着在请求设置的指令,在响应中不一定包含相同的指令。
    * 禁止缓存
    Cache-Control: no-cache, no-store, must-revalidate
    * 缓存静态资源
    对于应用程序中不会改变的文件,你通常可以在发送响应头前添加积极缓存。
    对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
    对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件。

    更多关于Cache-Control参考:MDN Cache-Control
    更多关于缓存参考:MDN HTTP caching

    4.使用 HTTP / 2.0

      因为浏览器会有并发请求限制,在 HTTP / 1.1 时代,每个请求都需要建立和断开,消耗了好几个 RTT 时间,并且由于 TCP 慢启动的原因,加载体积大的文件会需要更多的时间。

      在 HTTP / 2.0 中引入了多路复用,能够让多个请求使用同一个 TCP 链接,极大的加快了网页的加载速度。并且还支持 Header 压缩,进一步的减少了请求的数据大小。

    5.防抖和节流

    debounce和throttle,
    防抖和节流的作用都是防止函数多次调用。在事件和函数执行之间加了一个控制层。

    防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
    指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

    /**  
     * @desc 函数防抖    
     * @param func 函数 
     * @param wait 延迟执行毫秒数 
     * @param immediate true 表立即执行,false 表非立即执行
     */ 
    function debounce(func,wait,immediate) { 
        let timeout; 
    return function () { 
            let context = this;               
            let args = arguments;       
    if (timeout) clearTimeout(timeout); 
            if (immediate) { 
                var callNow = !timeout;                     
                timeout = setTimeout(() => {
                    timeout = null;                               
                }, wait) 
                if (callNow) func.apply(context, args)
            }             
            else { 
                timeout = setTimeout(function(){
                    func.apply(context, args)      
                }, wait);                                 
            }    
        }                                                              
    }                                                                  
    

    所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。
    时间戳版和定时器版。

    /**
     * @desc 函数节流
     * @param func 函数
     * @param wait 延迟执行毫秒数
     * @param type 1 表时间戳版,2 表定时器版
     */
    function throttle(func, wait ,type) {
        if(type===1){
            let previous = 0;
        }else if(type===2){
            let timeout;
        }
        return function() {
            let context = this;
            let args = arguments;
            if(type===1){
                let now = Date.now();
    		     if (now - previous > wait) {
             func.apply(context, args);
             previous = now;
       }
    }else if(type===2){
          if (!timeout) {
               timeout = setTimeout(() => {
                   timeout = null;
                   func.apply(context, args)
               }, wait);
           }
    	}
    }
    
  • 相关阅读:
    电脑自动登录
    修改电脑AppData位置
    MySQL_Navicat for MySQL设置定时备份
    MySQL_获取2个日期之间的所有日期
    MySQL_分页优化
    MySQL_1055错误代码与sql_mode = only_full_group_by不兼容
    MySQL_通过Binlog日志恢复数据库
    【Windows核心编程】如何知道程序运行中当前操作的内存地址范围,自己实现一个文件映射类
    整理后JS基础的封装
    git从本地仓库迁移到远程仓库
  • 原文地址:https://www.cnblogs.com/mthz/p/web7.html
Copyright © 2020-2023  润新知