前端性能优化+代码示例

前言

现在确实有好多性能优化方面的文章,但好多都只是文字讲解,马上下班了,抽点时间总结总结。

前端性能优化的原则其实就是更好的用户体验,具体实现的目标大体有两个:

  1. 合理使用内存或缓存,减少请求;
  2. 减少CPU或者GPU的计算,达到更快的展现。

前端在性能优化的方向大体有两个:

  1. 减少页面体积,提升网络加载
  2. 优化页面渲染

正文

一.减少页面体积,提升网络加载

1、静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)

  1. 压缩是为了减小文件体积,减轻网络负载,达到更快的下载;
  2. 合并和雪碧图都是为了减少文件的请求次数,但不是合并的就一个比没有合并时加载快,要看合并之后的体积,若文件合并后太大了也不太利于性能优化,所以在实际的项目中要做好权衡。

2、静态资源缓存(资源名称加 MD5 戳)

      可以通过链接名称控制缓存:通过前端构建工具为打包的文件添加md5后缀,这样当打包上线时请求的链接发生改变,这样可以防止由于缓导致静态资源更新失效;

3、 使用 CDN 让资源加载更快

二.优化页面渲染

1、CSS 放前面,JS 放后面

  1. 浏览器在渲染解析过程中,若遇到<link href="..."><script src="...">这种外链加载 CSS 和 JS 的标签,浏览器会异步下载并解析执行。CSS放在头部是为了让浏览器尽早解析执行Css文件,渲染出页面的样式,若放在底部会出现渲染卡顿的情况,影响性能和体验。
  2. 而当渲染过程中遇到script标签时就会执行JS代码,从阻塞页面渲染,因为浏览器渲染和 JS 执行共用一个线程,而且这里必须是单线程操作,多线程会产生渲染 DOM 冲突。所以要将JS放在底部,等到页面渲染完成之后再去解析执行js,保证用户体验性。因为浏览器渲染和 JS 执行共用一个线程,而且这里必须是单线程操作,多线程会产生渲染 DOM 冲突。
  3. 另外,JS 执行如果涉及 DOM 操作,得等待 DOM 解析完成才行,JS 放在底部执行时,HTML 肯定都解析成了 DOM 结构。JS 如果放在 HTML 顶部,JS 执行的时候 HTML 还没来得及转换为 DOM 结构,可能会报错。

2、懒加载(图片懒加载、下拉加载更多)

先将src赋值成一个通用的预览图,下拉时候再动态赋值成正式的图片。如下,preview.png是预览图片,比较小,加载很快,而且很多图片都共用这个preview.png,加载一次即可。待页面下拉,图片显示出来时,再去替换src为data-src的值。(data-开头的属性浏览器渲染的时候会忽略掉,提高渲染性能)

<img src="preview.png" data-src="realImg.png"/>

3、减少DOM 查询,对 DOM 查询做缓存

    // 只查询一个 DOM ,缓存在 pList 中了
    var pList = document.getElementsByTagName('p')  
    for (var i = 0; i < pList.length; i++) {
    }
    // 每次循环,都会查询 DOM ,耗费性能
    for (var i = 0; i < document.getElementsByTagName('p').length; i++) {
    }

4、减少DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)

DOM 操作是非常耗费性能的,因此插入多个标签时,先插入 Fragment 然后再统一插入 DOM。因为Fragment文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流。

    var listNode = document.getElementById('list')
    // 要插入 10 个 li 标签
    var frag = document.createDocumentFragment();
    var i, li;
    for(i = 0; i < 10; i++) {
        li = document.createElement("li");
        li.innerHTML = "List item " + i;
        frag.appendChild(li);  //先放在 frag 中,最后一次性插入到 DOM 结构中。
    }
    listNode.appendChild(frag);

5、事件节流

在开发过程中会遇到页面一些频繁触发的事件,比如mouseover、scroll、resize等事件。一秒可以执行很多次,这样会造成严重的页面性能问题,导致页面c出现卡顿甚至浏览器崩溃。因此我们需要对事件进行节流,简单的说就是控制其执行的次数。这里就涉及到了常用到的js的节流和防抖功能实现。
       1.防抖(debounce):在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

    function debounce(fn, delay) {
        // 定时器,用来 setTimeout
        var timer
        // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
        return function () {
            // 保存函数调用时的上下文和参数,传递给 fn
            var context = this
            var args = arguments
            // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
            timer && clearTimeout(timer)
            // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
            // 再过 delay 毫秒就执行 fn
            timer = setTimeout(function () {
                fn.apply(context, args)
            }, delay)
        }
    }

     2、节流(throttle):规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

    function throttle(fn, threshhold) {
        // 记录上次执行的时间
        var last
        // 定时器
        var timer
        // 默认间隔为 250ms
        threshhold || (threshhold = 250)
        // 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数
        return function () {
            // 保存函数调用时的上下文和参数,传递给 fn
            var context = this
            var args = arguments
            var now = +new Date()
            // 如果距离上次执行 fn 函数的时间小于 threshhold,那么就放弃
            // 执行 fn,并重新计时
            if (last && now < last + threshhold) {
                timer && clearTimeout(timer)
                // 保证在当前时间区间结束后,再执行一次 fn
                timer = setTimeout(function () {
                    last = now
                    fn.apply(context, args)
                }, threshhold)
            // 在时间区间的最开始和到达指定间隔的时候执行一次 fn
            } else {
                last = now
                fn.apply(context, args)
            }
        }
    }

6、尽早执行操作(DOMContentLoaded) 

    window.addEventListener('load', function () {
        // 页面的全部资源加载完才会执行,包括图片、视频等
    })
    document.addEventListener('DOMContentLoaded', function () {
        // DOM 渲染完即可执行,此时图片、视频还可能没有加载完
    })
    $(document).ready({function () {
        // 同DOMContentLoaded
    })

7、使用 预渲染 或者 SSR后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS 模板渲染页面 HTML 的时间 (如Vue SSR),同时也有利于网站的SEO。

最后

感谢各位的阅读,如有问题麻烦及时指正出来。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章