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


    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 += '<span class="slider-indicator"></span>';
                    }
    
                    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 () {});
    
            //原生js
            sliderIndicatorContainer.addEventListener('click', function (ev) {
                // console.log(ev.target);//ev.target获取到当前点击的元素
                if (ev.target && /(^|s)slider-indicator($|s)/.test(ev.target.className)) {
                    //正则判断当前点击的元素的className
                    console.log('click');
                }
            }, false);

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

    比如 scroll resize mousemove touchmove等事件

            // 事件节流
            // scroll resize mousemove touchmove
            var 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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">1000</strong></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超高清HDR</p>
                            <p class="recommend-origPrice">
                                <del>¥2999.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">2299</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">299</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">108</strong></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.40</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">89.9</strong></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.90</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">89.9</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">169</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">268</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">159</strong></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.00</del>
                            </p>
                            <p class="recommend-info">
                                <span class="recommend-price">¥<strong class="recommend-price-num">29.9</strong></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.js
    
                    window.removeEventListener('scroll', loadProduct, false);
                }
            }

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

    常用于浏览漫画的时候

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

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

  • 相关阅读:
    跨域请求携带cookie
    vue keep-alive
    关于js replace 第二个参数时函数时,函数参数解析
    前端开发规范之CSS
    git命令集合(正在完善中...)
    怎么写jQuery的插件
    git命令集合
    GitHub创建静态网站预览方法
    正则表达式
    各种浏览器全屏模式的方法、属性和事件介绍
  • 原文地址:https://www.cnblogs.com/chenyingying0/p/12511552.html
Copyright © 2020-2023  润新知