关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

移动端性能优化(JavaScript性能优化)

发布时间:2020-03-18 00:00:00

JavaScript性能优化

 

DOM操作优化

查找DOM元素能用id就用id,是最高效的查找方法(还得看具体环境)

document.getElementById('slider')

 

从document开始查找子元素效率不高,建议从具体父元素开始查找

减少元素查找的层级

            var sliderItemContainer = document.querySelector('.slider-item-container');//从DOM开始查找var sliderItemContainer = sliderEl.querySelector('.slider-item-container');//从具体元素开始查找

 

DOM操作完使用变量缓存,否则需要多次操作DOM就得多次获取

            // 合理缓存DOM对象var sliderItemContainer = sliderEl.querySelector('.slider-item-container'),
                sliderItem = sliderItemContainer.querySelectorAll('.slider-item'),
                indicatorContainer = document.createElement('div');

 

在循环中操作字符串,最后再操作DOM;比每次循环操作DOM要好得多

不推荐

            for (var i = 0, num = sliderItem.length; i < num; i++) {
                 indicatorContainer.innerHTML += '<span class="slid
             }

推荐

            // 减少操作DOM的次数var html="";for (var i = 0, num = sliderItem.length; i < num; i++) {
                html += '';
                }

                indicatorContainer.innerHTML=html ;
            }

也可以使用文档碎片,因为还没有被渲染呈现,因此循环中不涉及DOM渲染 

在循环外只创建一遍文档碎片节点,在循环内克隆节点即可,传入true可以带内容一起拷贝

           var indicatorItemFragment = document.createDocumentFragment();//创建文档片段   var spanEl = document.createElement('span');// 减少操作DOM的次数for (var i = 0, num = sliderItem.length; i < num; i++) {var indicatorItem = spanEl.cloneNode(true);
                indicatorItem.className = 'slider-indicator';indicatorItemFragment.appendChild(indicatorItem);
            }

 

循环的长度也用变量保存下来,只在最初执行一次

不推荐

for (var i = 0; i < sliderItem.length; i++)

推荐

for (var i = 0, num = sliderItem.length; i < num; i++)

 

不要直接修改style,通过添加class修改
直接修改style,如果修改的内容多,需要多次操作DOM;另外会涉及重排和重绘
重排涉及元素的位置关系变化,重绘涉及到元素的颜色透明度等
重绘影响性能,重排比重绘更耗性能,因此需要减少重绘,避免重排
不推荐
                // 不要直接修改style,通过添加class修改if (i === activeIndex) {
                    indicatorItem.style.backgroundColor = '#007aff';
                    indicatorItem.style.opacity = 1;// 重排 重绘}

推荐

                // 不要直接修改style,通过添加class修改if (i === activeIndex) {
                    indicatorItem.className += ' slider-indicator-active';
                }

 

事件的优化:

避免事件多次绑定,而且如果改变节点时还需要增加或解除绑定

避免遍历节点,给每个元素都绑定事件

可以使用事件代理或者事件委托,给它们的父元素绑定一次事件即可(事件冒泡原理)

不推荐

        var sliderEl = document.getElementById('slider'),
            sliderIndicatorContainer = sliderEl.querySelector('.slider-indicator-container'),
            sliderIndicators = sliderIndicatorContainer.querySelectorAll('.slider-indicator');// 事件绑定for (var i = 0, num = sliderIndicators.length; i < num; i++) {
            sliderIndicators[i].addEventListener('click', function () {
                console.log('click');
            }, false);
        }// 动态插入一个新节点var sliderIndicator = document.createElement('span');
        sliderIndicator.className = 'slider-indicator';
        sliderIndicatorContainer.appendChild(sliderIndicator);
        sliderIndicator.addEventListener('click', function () {
            console.log('click');
        }, false);

推荐

        // 使用事件代理,避免直接事件绑定// jQuery/Zepto$(sliderIndicatorContainer).on('click', '.slider-indicator', function () {});//原生jssliderIndicatorContainer.addEventListener('click', function (ev) {// console.log(ev.target);//ev.target获取到当前点击的元素if (ev.target && /(^|\s)slider\-indicator($|\s)/.test(ev.target.className)) {//正则判断当前点击的元素的classNameconsole.log('click');
            }
        }, false);

 

针对执行非常频繁的事件,使用事件节流来稀释

比如 scroll resize mousemove touchmove等事件

        // 事件节流// scroll resize mousemove touchmovevar timer = null;
        window.addEventListener('scroll', function () {
            console.log('scroll');//不节流//100ms内有重复执行,则取消前面的执行            clearTimeout(timer);
            timer = setTimeout(function () {
                console.log('scroll');//节流}, 100);// ....}, false);

 

 

资源按需加载(懒加载,延迟加载)

将img的src属性可以先放在data-src(自定义属性)里,默认src里放一个统一的loading小图标

给需要按需加载的图片添加一个统一的类

<img src="img/loading.gif" data-src="img/recommend/1.jpg" alt="recommend" class="recommend-img lazyload-img">

获取到所有需要按需加载的图片节点,存入数组中

        var lazyLoadClass = '.lazyload-img';//Array.prototype.slice.call()类数组转数组var imgArr = Array.prototype.slice.call(document.querySelectorAll(lazyLoadClass));//获取到所有需要按需加载的节点列表,转数组console.log(imgArr);

 

 初始化时和每次滚动时,都执行按需加载函数

        lazyLoadImgs();//初始化时执行图片加载//每次滚动时也执行图片加载var timer = null;
        window.addEventListener('scroll', function () {
            clearTimeout(timer);
            timer = setTimeout(function () {
                lazyLoadImgs();
            }, 100);
        }, false);

判断元素是否在可视区内

        // 是否在页面可视区内function isInVisibleArea(el) {var rect = el.getBoundingClientRect();// rect.top 可视区顶部到物体顶部// rect.bottom  可视区底部到物体底部// rect.right 可视区右边到物体右边// rect.left 可视区左边到物体左边return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
        }

按需加载函数

        function lazyLoadImgs() {for (var i = 0; i < imgArr.length; i++) {//判断是否在可视区范围if (isInVisibleArea(imgArr[i])) {
                    imgArr[i].src = imgArr[i].getAttribute('data-src');//用data-src属性填充到src属性中imgArr.splice(i, 1);//数组中剔除已经加载的图片i--;//数组长度减少                }
            }
        }

完整代码:

<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"><title>4.3 资源按需加载和预加载title><link rel="stylesheet" href="css/base.css"><link rel="stylesheet" href="css/icons.css"><link rel="stylesheet" href="css/index.css"><script src="js/flexible.js">script>head><body><header class="header-container"><div class="navbar"><div class="navbar-left"><i class="iconfont icon-scan">i>div><div class="navbar-center"><div class="searchBox"><div class="searchBox-prepend"><i class="iconfont icon-search">i>div><input type="text" placeholder="开学季有礼,好货5折起" class="searchBox-input"><div class="searchBox-append"><i class="iconfont icon-close">i>div>div>div><div class="navbar-right"><i class="iconfont icon-msg">i>div>div>header><div class="main-container"><div class="slider-container"><img src="img/slider/1.jpg" alt="slider">div><nav class="nav-container"><ul class="nav"><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/1.png" alt="nav" class="nav-img"><span class="nav-text">团购span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/2.png" alt="nav" class="nav-img"><span class="nav-text">一元购span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/3.png" alt="nav" class="nav-img"><span class="nav-text">优惠券span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/4.png" alt="nav" class="nav-img"><span class="nav-text">教育span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/5.png" alt="nav" class="nav-img"><span class="nav-text">旅行span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/6.png" alt="nav" class="nav-img"><span class="nav-text">在线订餐span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/7.png" alt="nav" class="nav-img"><span class="nav-text">庆典span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/8.png" alt="nav" class="nav-img"><span class="nav-text">秒杀span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/9.png" alt="nav" class="nav-img"><span class="nav-text">拍卖span>a>li><li class="nav-item"><a href="###" class="nav-link"><img src="img/nav/10.png" alt="nav" class="nav-img"><span class="nav-text">服务span>a>li>ul>nav><div class="recommend-container"><ul class="recommend"><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/1.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">欧派整体橱柜定制简约现代p><p class="recommend-origPrice"><del>¥2000.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">1000strong>span><span class="recommend-count">985件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/2.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">创维55吋4K超高清HDRp><p class="recommend-origPrice"><del>¥2999.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">2299strong>span><span class="recommend-count">63件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/3.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">【到手259元】苏泊尔 5L电压力锅p><p class="recommend-origPrice"><del>¥799.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">299strong>span><span class="recommend-count">1908件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/4.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">三只松鼠坚果礼包p><p class="recommend-origPrice"><del>¥125.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">108strong>span><span class="recommend-count">9532件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/5.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">蓝月亮洗衣液12斤p><p class="recommend-origPrice"><del>¥133.40del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">89.9strong>span><span class="recommend-count">5399件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/6.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">福临门葵花玉米油p><p class="recommend-origPrice"><del>¥109.90del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">89.9strong>span><span class="recommend-count">6294件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/7.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">TP-LINK 全千兆端口双频无线路由器p><p class="recommend-origPrice"><del>¥179.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">169strong>span><span class="recommend-count">4255件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/8.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">【前1800名再减50】家用高压洗车机p><p class="recommend-origPrice"><del>¥790.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">268strong>span><span class="recommend-count">1599件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/9.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">德国鲁茜rusch迷你婴儿辅食机 宝宝p><p class="recommend-origPrice"><del>¥898.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">159strong>span><span class="recommend-count">881件已售span>p>a>li><li class="recommend-item"><a href="###" class="recommend-link"><p class="recommend-pic"><img src="img/loading.gif" data-src="img/recommend/10.jpg" alt="recommend" class="recommend-img lazyload-img">p><p class="recommend-name">西域之尚红枣500g*5袋p><p class="recommend-origPrice"><del>¥89.00del>p><p class="recommend-info"><span class="recommend-price">¥<strong class="recommend-price-num">29.9strong>span><span class="recommend-count">15049件已售span>p>a>li>ul>div> 资源按需加载 --><div id="product" class="product" style="height: 500px; background-color: red; text-align: center; line-height: 500px; font-size: 2.5rem; color: #fff;"><img src="img/loading.gif" alt="">div>div><div class="tabbar-container"><ul class="tabbar"><li class="tabbar-item tabbar-item-active"><a href="###" class="tabbar-link"><i class="iconfont icon-home">i><span>首页span>a>li><li class="tabbar-item"><a href="###" class="tabbar-link"><i class="iconfont icon-category">i><span>分类页span>a>li><li class="tabbar-item"><a href="###" class="tabbar-link"><i class="iconfont icon-cart">i><span>购物车span>a>li><li class="tabbar-item"><a href="###" class="tabbar-link"><i class="iconfont icon-personal">i><span>个人中心span>a>li>ul>div><script>// 1. 图片的按需加载var lazyLoadClass = '.lazyload-img';//Array.prototype.slice.call()类数组转数组var imgArr = Array.prototype.slice.call(document.querySelectorAll(lazyLoadClass));//获取到所有需要按需加载的节点列表,转数组console.log(imgArr);

        lazyLoadImgs();//初始化时执行图片加载//每次滚动时也执行图片加载var timer = null;
        window.addEventListener('scroll', function () {
            clearTimeout(timer);
            timer = setTimeout(function () {
                lazyLoadImgs();
            }, 100);
        }, false);function lazyLoadImgs() {for (var i = 0; i < imgArr.length; i++) {//判断是否在可视区范围if (isInVisibleArea(imgArr[i])) {
                    imgArr[i].src = imgArr[i].getAttribute('data-src');//用data-src属性填充到src属性中                    imgArr.splice(i, 1);//数组中剔除已经加载的图片                    i--;//数组长度减少                }
            }
        }// 是否在页面可视区内function isInVisibleArea(el) {var rect = el.getBoundingClientRect();// rect.top 可视区顶部到物体顶部// rect.bottom  可视区底部到物体底部// rect.right 可视区右边到物体右边// rect.left 可视区左边到物体左边return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
        }script>body>html>

 

 

 

 

其他资源的按需加载

js/loadProduct.js
(function () {var product = document.getElementById('product');

    product.innerHTML = '我是按需加载的';
})();

html中代码添加:

        // 2. 其他内容的按需加载        loadProduct();
        window.addEventListener('scroll', loadProduct, false);function loadProduct() {if (isInVisibleArea(document.getElementById('product'))) {var script = document.createElement('script');// script.src = 'js/loadProduct.js';//使用setTimeout是为了模拟网络延迟,上线时不需要延迟setTimeout(function () {
                    script.src = 'js/loadProduct.js';
                }, 1000);
                document.body.appendChild(script);//载入loadProduct.jswindow.removeEventListener('scroll', loadProduct, false);
            }
        }

 

 

 

预加载(空闲的时候加载,之后用到的时候已经加载完了)

常用于浏览漫画的时候

        // 3. 图片预加载var img = new Image();
        img.src = 'img/recommend/5.jpg';

 

 (还没滚动就已经预加载了)

 

 


/template/Home/Zkeys/PC/Static