天天看点

h5首页加载慢_前端性能优化之预加载和懒加载

h5首页加载慢_前端性能优化之预加载和懒加载

老项目优化第二步——资源的懒加载和预加载

之前做前端项目性能优化的时候,为了使页面加载更快,用尽了手段,包括文件的合并、压缩,文件缓存和开启服务器端的 gzip 压缩等等。

但发现压缩总有个极限,并且遇到弱网环境时,用户在感知上依旧会有“慢”的概念,尤其是在首屏展示的时候,于是就选了两种方案(骨架屏和资源预加载,骨架屏下次再总结)。

预加载

预加载相信很多人都有听说过,引用Patrick Hamann的解释就是,预加载是浏览器对将来可能被使用资源的一种暗示,一些资源可以在当前页面使用到,一些可能在将来的某些页面中被使用。

简单理解就是,将页面加载时的资源提前加载到本地,等页面真正加载时直接从缓存获取资源。

h5首页加载慢_前端性能优化之预加载和懒加载

我主要是使用在首屏加载时需要的资源,以及一个资源过大的文件上,避免页面长时间空白,减少等待时间,优化体验。

预加载可以细分为以下几个点:DNS-prefetch、subresource 、 prefetch、preconnect、prerender。

可根据自己项目需要去使用。

(1)DNS 预解析 DNS-Prefetch

通过 DNS 预解析来告诉浏览器未来我们可能从某个特定的 URL 获取资源,当浏览器真正使用到该域中的某个资源时就可以尽快地完成 DNS 解析。比如说,我们可能从 http://example.com 获取资源时(图片、音频等),就可以在<head> 标签中加入以下内容:

<link rel="dns-prefetch" href="//example.com" target="_blank" rel="external nofollow" >
           

当我们从该 URL 请求一个资源时,就不再需要等待 DNS 的解析过程。

(2)预连接 Preconnect

与 DNS 预解析类似,preconnect 不仅完成 DNS 预解析,同时还将进行 TCP 握手和建立传输层协议。可以这样使用:

<link rel="preconnect" href="http://example.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >
           

(3)预获取 Prefetching

如果我们确定某个资源将来一定会被使用到,我们可以让浏览器预先请求该资源并放入浏览器缓存中,也就是说如果我们猜测用户接下来将要访问哪个具体的资源,那就可以用prefetching来预加载确定的资源了。

<link rel="prefetch" href="image.png" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >
           

(4)Subresources

这是另一个预获取方式,这种方式指定的预获取资源具有最高的优先级,在所有 prefetch 项之前进行:

<link rel="subresource" href="styles.css" target="_blank" rel="external nofollow" >
           

prefetch 为将来的页面提供了一种低优先级的资源预加载方式,而subresource 为当前页面提供了一种高优先级的资源预加载。

如果资源是当前页面必须的,或者资源需要尽快可用,那么最好使用 subresource 而不是 prefetch。

(5)预渲染 Prerender

prerender 可以预先加载文档的所有资源,类似于在隐藏的tab 页中打开了某个链接 – 将下载所有资源、创建 DOM 结构、完成页面布局、应用 CSS 样式和执行 JavaScript 脚本等。

当用户真正访问该链接时,隐藏的页面就切换为可见,使页面看起来就是瞬间加载完成一样。

<link rel="prerender" href="http://example.com" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >
           

需要注意的是不要滥用该特性,当你知道用户一定会点击某个链接时才可以进行预渲染,否则浏览器将无条件地下载所有预渲染需要的资源。

(6)新特性:Preloading

和prefetching不同,preloading会让浏览器无论如何都下载指定的资源,也就是说浏览器一定会预加载该资源。

<link rel="preload" href="image.png" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >
           

所有预加载技术都存在一个潜在的风险:对资源预测错误。

而预加载的开销是高昂的,比如抢占 CPU 资源,消耗电池,浪费带宽等,所以必须谨慎行事。

虽然很难确定用户下一步将访问哪些资源,但高可信的场景确实存在:

  • 如果用户完成一个带有明显结果的搜索,那么结果页面很可能会被加载。
  • 如果用户进入到登陆页面,那么登陆成功的页面很可能会被加载。
  • 如果用户阅读一个多页的文章或访问一个分页的结果集,那么下一页很可能会被加载。

(7)H5音乐预加载 preload=”auto”

<audio src="audio.mp3" autoplay="autoplay" loop preload="auto" id="sendid2"></audio> 
           

(8)使用html标签

<img src="image.png" style="display:none"/>
           

(9)使用Image对象

<script src="./imagePreload.js"></script>

// imagePreload.js文件
var image= new Image()
image.src="https://xxx.xx.com/image.jpg"
           

优化网页性能的另一种方式, 懒加载

图片懒加载

图片懒加载一般用于网页中延迟加载图像,用户滚动到它们之前,可视区域外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。

使用懒加载是为了应对那些页面过长,图片资源过多的网页。如果要等整个页面一次性加载完成,那体验就太差了。

实现原理
  • 首先,不要将图片地址放到src属性中,而是放到其它属性(data-original)中。
  • 页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中。
  • 在滚动事件中重复判断图片是否进入视野,如果进入,则将data-original属性中的值取出存放到src属性中。
// 图片懒加载
<html >

<head>
    <meta charset="UTF-8">
    <title>Lazyload</title>
    <style>
        .image-item {
            display: block;
            margin-bottom: 50px;
            height: 200px; // 一定记得设置图片高度
        }
    </style>
</head>

<body>
    <img src="" class="image-item" lazyload="true" data-original="images/1.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/2.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/3.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/4.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/5.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/6.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/7.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/8.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/9.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/10.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/11.png" />
    <img src="" class="image-item" lazyload="true" data-original="images/12.png" />
    <script>
        var viewHeight = document.documentElement.clientHeight // 获取可视区高度
        function lazyload() {
            var eles = document.querySelectorAll('img[data-original][lazyload]')
            Array.prototype.forEach.call(eles, function (item, index) {
                var rect
                if (item.dataset.original === "")
                    return
                rect = item.getBoundingClientRect() // 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
                if (rect.bottom >= 0 && rect.top < viewHeight) {
                    !function () {
                        var img = new Image()
                        img.src = item.dataset.original
                        img.onload = function () {
                            item.src = img.src
                        }
                        item.removeAttribute("data-original")// 移除属性,下次不再遍历
                        item.removeAttribute("lazyload")
                    }()
                }
            })
        }
        lazyload() // 刚开始还没滚动屏幕时,要先触发一次函数,初始化首页的页面图片
        document.addEventListener("scroll",lazyload)
    </script>
</body>

</html>
           

懒加载库

Github上也有很多懒加载库可以直接引用:

  • lazysizes 是一个功能十分强大的懒加载库,主要用于加载图片和iframes。你只需要指定src/srcset属性,lazysizes会帮你自动懒加载内容。值得注意的是,lazysizes基于intersection observer,因此你需要一个polyfill。你还可以通过一些插件扩展库的功能以用于懒加载视频。
  • lozad.js是一个轻量级、高性能的懒加载库,基于intersection observer,你同样需要提供一个相关的polyfill。
  • blazy是一个轻量级的懒加载库,大小仅为1.4KB。相对于lazysizes,它不需要任何的外部依赖,并且兼容IE7+。你可能猜测到了,blazy不支持intersection observer,性能相对较差。
  • react-lazyload基于react的懒加载组件。

Vue路由懒加载(组件按需加载)

在单页应用中,运用webpack打包后的文件随着项目的进行会变得很大,组件越来越多,首次启动项目时,需要加载的内容过多,延时过长,不利于用户体验。

运用懒加载可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载时间。

与webpack配合实现组件懒加载

(1)在webpack配置文件中的output路径配置chunkFilename属性

output: {
        path: resolve(__dirname, 'dist'),
        filename: options.dev ? '[name].js': '[name].js?[chunkhash]',
        chunkFilename: 'chunk[id].js?[chunkhash]',
        publicPath: options.dev ? '/assets/': publicPath
},
// chunkFilename路径将会作为组件懒加载的路径
           

(2)配合webpack支持的异步加载方法

// resolve => require([URL], resolve), 支持性好
// () => system.import(URL) , webpack2官网上已经声明将逐渐废除, 不推荐使用
// () => import(URL), webpack2官网推荐使用, 属于es7范畴, 需要配合babel的syntax-dynamic-import插件使用, 具体使用方法如下

npm install --save-dev babel-core babel-loader babel-plugin-syntax-dynamic-importbabel-preset-es2015
use: [{
        loader: 'babel-loader',
        options: {
          presets: [['es2015', {modules: false}]],
          plugins: ['syntax-dynamic-import']
        }
      }]
           
具体实例中实现懒加载

(1)路由中配置异步组件

export default new Router({
    routes: [
        {
            mode: 'history',
            path: '/home,
            name: home,
            component:  resolve => require(['../views/home.vue'], resolve) // 懒加载
        },
    ]
})
           

(2)实例中配置异步组件

components: {
        historyTab: resolve => {require(['../../component/page.vue'], resolve)} // 懒加载   
}
           

(3)全局注册异步组件

Vue.component(‘header’, () => {
    System.import('./component/header.vue')
})
           

以上是这次项目优化在加载这方面整理的材料,后续会持续更新欢迎各位朋友指正