likes
comments
collection
share

前端性能优化技巧之懒加载和Webpack

作者站长头像
站长
· 阅读数 3

图片懒加载原理

1.懒加载概念

图片懒加载也叫延迟加载,只加载当前屏幕的图片,可视区域外的图片不会进行加载,只有当屏幕滚动的时候才加载。

2.懒加载的特点

  • 提高网页加载速度
  • 减少后台服务器压力
  • 提升用户体验

3.懒加载的实现原理

图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5的 data-xxx 属性来储存图片的路径,在需要加载图片的时候,将 data-xxx 中图片的路径赋值给 src,这样就实现了图片的按需加载,即懒加载。

  • 将图片地址存储到data-xxx属性上
  • 判断图片是否在可视区域
  • 如果在,就设置图片src
  • 绑定scroll监听事件

注意: data-xxx 中的 xxx 可以自定义,这里我们使用 data-src 来定义。

懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。

使用原生JavaScript实现懒加载: 知识点:

  1. window.innerHeight 是浏览器可视区的高度
  2. document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动的过的距离
  3. imgs.offsetTop 是元素顶部距离文档顶部的高度 (包括滚动条的距离)
  4. 图片加载条件: img.offsetTop < window.innerHeight + document.body.scrollTop;

图示 前端性能优化技巧之懒加载和Webpack

代码实现

<div class="container">
    <img src="loading.gif" data-src="pic.png">
    <img src="loading.gif" data-src="pic.png">
    <img src="loading.gif" data-src="pic.png">
    <img src="loading.gif" data-src="pic.png">
    <img src="loading.gif" data-src="pic.png">
    <img src="loading.gif" data-src="pic.png">
</div>
<script>
    var imgs = document.queryselectorAll('img');
    function lozyLoad(){
        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        var winHeight= window.innerHeight;
        for(var i=0;i < imgs.length;i++){
            if(imgs[i].offsetTop < scrollTop + winHeight ){
                imgs[i].src = imgs[i].getAttribute('data-src');
            }
        }
    }
    window.onscroll = lozyLoad();
</script>

4.懒加载与预加载的区别

这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

  • 懒加载也叫延迟加载,指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。

  • 预加载指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。

webpack

如何提高Webpack打包速度?

1. 优化Loader(缩小打包范围)

对于 Loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低,当然了这是可以优化的。

首先我们优化 Loader 的文件搜索范围,我们可以通过缩小Webpack要打包的范围来提高打包速度。方法是在Webpack配置文件中使用exclude或include属性。我们可以将不需要打包的文件或目录原则上设置为exclude,而只需要打包的文件或目录可以设置为include。这样做可以帮助Webpack减少不必要的文件解析和处理。

module.exports = {
    module: {
        rules:[
            {
             //js 文件才使用babel
             test: /\.js$/,
             loader:"babel-loader"
             // 只在 src 文件夹下查找
             include: [resolve( 'src')],
             //不会去查找的路径
             exclude: /node modules/
            }
        ]
    }
}

对于 Babel 来说,希望只作用在JS 代码上的,然后 node modules 中使用的代码都是编译过的,所以完全没有必要再去处理一遍。 当然这样做还不够,还可以将 Babel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间

loader:"babel-loader?cacheDirectory=true"

2. HappyPack

受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。

HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了

module: {
    loaders:[
        {
            test: /\.js$/,
            include: [resolve('src')],
            exclude: /node modules/
            // id 后面的内容对应下面
            loader:happypack/loader?id=happybabel
        }
    ]
},
plugins:[
    new HappyPack({
        id:"happybabel
        loaders: ["babel-loader?cacheDirectory"],
        // 开启 4 个线程
        threads: 4
    })
]

3. DllPlugin

DLL Plugin是一种特殊的插件,它可以将稳定的代码打包成一个单独的动态链接库,这样我们就可以在开发时可以只需要打包自己开发的代码而不需要打包所有依赖的第三方库,从而大大缩短了Webpack的打包时间。每次打包只需要使用动态链接库即可,而不需要重新打包整个项目。

Webpack提供了一个DllPlugin插件来实现动态链接库的打包。我们可以在配置文件中设置entry属性,并将需要单独打包的模块作为数组传入,进行打包。

DllPlugin 可以将特定的类库提前打包然后引入。这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。DlIPlugin的使用方法如下:

// webpack.conf.js
module.exports = {
    // ...省略其他配置
    plugins:[
        new webpack.DllReferencePlugin({
            context:_dirname,
            // manifest 就是之前打包出来的 json 文件
            manifest: require('./dist/vendor-manifest.json')
        })
    ]
}

在主配置文件中,我们需要使用DllReferencePlugin插件来引用动态链接库,将依赖文件引入项目中

// webpack.conf.js
module.exports = {
    // ...省略其他配置
    plugins:[
        new webpack.DllReferencePlugin({
            context:_dirname,
            // manifest 就是之前打包出来的 json 文件
            manifest: require('./dist/vendor-manifest.json')
        })
    ]
}

4. 代码压缩

在 Webpack3 中,一般使用 UglifyJs 来压缩代码,但是这个是单线程运行的,为了加快效率,可以使用 webpack-parallel-uglify-plugin 来并行运行 UglifyJs ,从而提高效率。

在 Webpack4 中,不需要以上这些操作了,只需要将 mode 设置为 production 就可以默认开启以上功能.代码压缩也是我们必做的性能优化方案,当然我们不止可以压缩JS 代码,还可以压缩 HTML、CSS 代码,并且在压缩JS 代码的过程中,我们还可以通过配置实现比如删除 console.log 这类代码的功能.

如何减少Webpack打包体积?

1.按需加载

在开发 SPA 项目的时候,项目中都会存在很多路由页面。如果将这些页面全部打包进一个 JS 文件的话,虽然将多个请求合并了,但是同样也加载了很多并不需要的代码,耗费了更长的时间。那么为了首页能更快地呈现给用户,希望首页能加载的文件体积越小越好,这时候就可以使用按需加载,将每个路由页面单独打包为一个文件。当然不仅仅路由可以按需加载,对于 loadash 这种大型类库同样可以使用这个功能。

按需加载的代码实现这里就不详细展开了,因为鉴于用的框架不同,实现起来都是不一样的。当然了,虽然他们的用法可能不同,但是底层的机制都是一样的。都是当使用的时候再去下载对应文件,返回一个 Promise,当 Promise 成功以后去执行回调。

2.Scope Hoisting

Scope Hoisting 会分析出模块之间的依赖关系,尽可能的把打包出来的模块合并到一个函数中去。

3.Tree shaking

Tree shaking 可以实现删除项目中未被引用的代码

如何用webpack来优化前端性能?

用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。

  1. 压缩代码: 删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的 UglifyJsPlugin和 ParallelUglifyPlugin 来压缩JS文件,利用 cssnano (css-loader?minimize) 来压缩css
  2. 利用CDN加速: 在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output 参数和各loader的 publicPath 参数来修改资源路径
  3. Tree shaking:将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数 --optimize.minimize 来实现
  4. Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载同时可以充分利用浏览器缓存
  5. 提取公共第三方库: SplitChunksluin插件来进行公共模块抽取,利用浏览器缓存可以长期缓存这些无需频繁变动的公共代码

如何提高webpack的构建速度?

  1. 多入口情况下,使用 CommonsChunkPlugin 来提取公共代码
  2. 通过 externals 配置来提取常用库
  3. 利用 DlIPlugin 和 DIReferencePlugin 预编译资源模块 通过 DliPlugin 来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过 DIIReferenceplugin 将预编译的模块加载进来。
  4. 使用 Happypack 实现多线程加速编译
  5. 使用 webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。原理上 webpack-uglify-parallel 采用了多核并行压缩来提升压缩速度
  6. 使用 Tree-shaking 和 Scope Hoisting 来剔除多余代码