当前位置: 首页 > article >正文

web前端面试题之webpack和其他

  1. webpack前端性能优化
  2. webpack前端性能优化——包体积压缩82%、打包速度提升65%

1.externals 提取公共依赖包,可以使用 externals 来提取这些依赖包,打包时可以忽略它 然后在 index.html 中使用 CDN 引入依赖

  <body>    <script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>    <script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>    <script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>    <script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>  </body>复制代码

2、组件库的按需引入

为什么没有使用 externals 的方式处理组件库呢?

externals缺点:直接在html内引入的,失去了按需引入的功能,只能引入组件库完整的js和css

组件库按需引入的原理:最终只引入指定组件和对应的样式

elementUI 需要借助 babel-plugin-component[1] 插件实现,插件的作用如下:

通过该插件,最终只引入指定组件和样式,来实现减少组件库体积大小

减小三方依赖的体积【很多没有用到的语言包

使用 moment-locales-webpack-plugin 插件,剔除掉无用的语言包

HappyPack 多线程打包

HappyPack 就能实现多线程打包,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程,来提升打包速度

Gzip压缩

html、js、css资源,使用 gzip 后通常可以将体积压缩70%以上

这里介绍下使用 webpack 进行 gzip 压缩的方式,使用 compression-webpack-plugin 插件

  1. 如何提高构建速度

功能和业务代码也会随着越多,相应的 webpack 的构建时间也会越来越久,构建时间与我们日常开发效率密切相关,当我们本地开发启动 devServer 或者 build 的时候,如果时间过长,会大大降低我们的工作效率,

常见的提升构建速度的手段有如下:

  • 优化 loader 配置
  • 合理使用 resolve.extensions
  • 优化 resolve.modules
  • 优化 resolve.alias
  • 使用 DLLPlugin 插件
  • 使用 cache-loader
  • terser 启动多线程
  • 合理使用 sourceMap

优化loader配置

在使用loader时,可以通过配置include、exclude、test属性来匹配部分文件,

module.exports = {
  module: {
    rules: [
      {
        // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
        test: /\.js$/,
        // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
        use: ['babel-loader?cacheDirectory'],
        // 只对项目根目录下的 src 目录中的文件采用 babel-loader
        include: path.resolve(__dirname, 'src'),
      },
    ]
  },
};

合理使用 resolve.extensions

通过resolve.extensions是解析到文件时自动添加拓展名

module.exports = {
    ...
    extensions:[".warm",".mjs",".js",".json"]
}

当我们配置的时候,则不要随便把所有后缀都写在里面,这会调用多次文件的查找,这样就会减慢打包速度

优化 resolve.alias

alias给一些常用的路径起一个别名,特别当我们的项目目录结构比较深的时候,一个文件的路径可能是./../../的形式

通过配置alias以减少查找过程

module.exports = {
    ...
    resolve:{
        alias:{
            "@":path.resolve(__dirname,'./src')
        }
    }
}

使用 cache-loader

在一些性能开销较大的 loader 之前添加 cache-loader,以将结果缓存到磁盘里,显著提升二次构建速度

保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用此 loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.ext$/,
                use: ['cache-loader', ...loaders],
                include: path.resolve('src'),
            },
        ],
    },
};

terser 启动多线程

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },
};

合理使用 sourceMap

打包生成 sourceMap 的时候,如果信息越详细,打包速度就会越慢。对应属性取值如下所示:

总结

可以看到,优化webpack构建的方式有很多,主要可以从优化搜索时间、缩小文件搜索范围、减少不必要的编译等方面入手

3.webpack的热更新

HMR 全称 Hot Module Replacement,可以理解为模块热替换,指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个应用

例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致整个应用的整体刷新,那页面中的状态信息都会丢失

如果使用的是 HMR,就可以实现只将修改的模块实时替换至应用中,不必完全刷新整个应用

在webpack中配置开启热模块也非常的简单,如下代码:

const webpack = require('webpack')
module.exports = {
  // ...
  devServer: {
    // 开启 HMR 特性
    hot: true
    // hotOnly: true
  }
}

通过上述这种配置,如果我们修改并保存css文件,确实能够以不刷新的形式更新到页面中

但是,当我们修改并保存js文件之后,页面依旧自动刷新了,这里并没有触发热模块

所以,HMR 并不像 Webpack 的其他特性一样可以开箱即用,需要有一些额外的操作

我们需要去指定哪些模块发生更新时进行HRM,如下代码:

if(module.hot){
    module.hot.accept('./util.js',()=>{
        console.log("util.js更新了")
    })
}

Loader与Plugin对应的概

  • loader 是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
  • plugin 赋予了 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader 无法实现的其他事

常见的babel和plugin

下面介绍几个常用的插件用法:

HtmlWebpackPlugin

在打包结束后,⾃动生成⼀个 html ⽂文件,并把打包生成的js 模块引⼊到该 html 中

clean-webpack-plugin

删除(清理)构建目录

mini-css-extract-plugin

提取 CSS 到一个单独的文件中

前端安全

token是什么

token一般存放在localstorage中,每次请求接口都会带上

封装一个ajax接口都要配置什么

timeout: 8000,

url: '/api/pay/v1/queryByOrderNo',

method: 'POST',

data: data

headers: {'Content-Type': 'application/x-www-form-urlencoded', token: token,}

Content-Type:来告诉服务端如何处理请求的数据

说说 JavaScript 数字精度丢失的问题,解决方案?

解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)

// 0.1 + 0.2
(0.1*10 + 0.2*10) / 10 == 0.3 // true

如何给localStorage设置一个过期时间?

,localstorage原生是不支持设置过期时间的,想要设置的话,就只能自己来封装一层逻辑来实现:

function set(key,value){
  var curtime = new Date().getTime();//获取当前时间
  localStorage.setItem(key,JSON.stringify({val:value,time:curtime}));//转换成json字符串序列
}
function get(key,exp)//exp是设置的过期时间
{
  var val = localStorage.getItem(key);//获取存储的元素
  var dataobj = JSON.parse(val);//解析出json对象
  if(new Date().getTime() - dataobj.time > exp)//如果当前时间-减去存储的元素在创建时候设置的时间 > 过期时间
  {
    console.log("expires");//提示过期
  }
  else{
    console.log("val="+dataobj.val);
  }
}

———————————————————————————————————————————

大文件上传-分片

说说大文件分片和断点续传

如果上传文件过大,比如500M 1G 2G 那么大,可能上传超时和服务器的限制。

解决上面的问题可以用到分片上传:,每次只上传很小的一部分 比如2M,多上传几次就可以啦。

File 继承了Blob的功能,Blob 对象表示原始数据,也就是二进制数据,它提供了对数据截取的方法slice

思路如下;

  • 把大文件进行使用slice分段,比如分段成每个2M,发送到服务器携带一个标志,这里暂时用当前的时间戳,用于标识一个完整的文件

  • 服务端保存各段文件

  • 浏览器端所有分片上传完成,发送给服务端一个合并文件的请求

  • 服务端根据文件标识、类型、各分片顺序进行文件合并

  • 删除分片文件

---------------------------------------------------------------------------------------------------------------------------------

大文件上传-断点续传

分片上传的方式并不完美,因为大文件上传并不是短时间内就上传完成,如果期间断网,页面刷新了仍然需要重头上传

所以现在要解决的问题是:如何检测这些分片,不再重新上传即可。

方案;【上传的时候和本地保存的已经上传的分片的hash值做比对,来解决重复上传的问题】

  • 为每个分段生成 hash 值,使用spark-md5 三方模块

  • 将上传成功的分段信息保存到localStorage【保存在客户端是最不保险的,最好让服务端增加一个接口。

  • 重新上传时,进行和本地分段 hash 值的对比,如果相同的话则跳过,继续下一个分段的上传

PS: 生成 hash 过程肯定也会耗费资源,但是和重新上传相比可以忽略不计了。

---------------------------------------------------------------------------------------------------------------------------------

JavaScript 中如何实现并发控制?【未完】

JavaScript 中如何实现并发控制?

async function asyncPool(poolLimit, array, iteratorFn) {
  const ret = []; // 存储所有的异步任务
  const executing = []; // 存储正在执行的异步任务
  for (const item of array) {
    // 调用iteratorFn函数创建异步任务
    const p = Promise.resolve().then(() => iteratorFn(item, array));
    ret.push(p); // 保存新的异步任务

    // 当poolLimit值小于或等于总任务个数时,进行并发控制
    if (poolLimit <= array.length) {
      // 当任务完成后,从正在执行的任务数组中移除已完成的任务
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e); // 保存正在执行的异步任务
      if (executing.length >= poolLimit) {
        await Promise.race(executing); // 等待较快的任务执行完成
      }
    }
  }
  return Promise.all(ret);
}

1.使用promise.race(),等待较快的任务执行完成

2.当每完成一个进行中的任务时,就移除已完成的任务

3.最后return Promise.all

---------------------------------------------------------------------------------------------------------------------------------

并发

并发:代表计算机能够同时执行多项任务

并行:对于多核处理器,可以在不同的核心上真正并行的执行任务

---------------------------------------------------------------------------------------------------------------------------------

JS while 循环的语法格式如下:

while (条件表达式) {
    // 要执行的代码
}

---------------------------------------------------------------------------------------------------------------------------------

JavaScript 中如何实现异步串行?

async/await!号称JS异步的终极解决方案,真不是盖的,下面就来看看async/await的方案,

一个for循环解决串行异步问题,没有回调没有嵌套看起来瞬间舒服多了~

var urlArr = ['http://www.qq.com','http://www.qq.com','http://www.qq.com'];
function makeRequest(url){
    return new Promise((resolve,reject)=>{
        $.get(url).success((ret)=>{
            resolve(ret)
        }).fail(()=>{
            reject()
        })
    })
}
async function makaPromiseList(dataArr,handler){
    var result = [];
    for(let item of dataArr){
        var ret = await handler(item);
        result.push(ret);
    }
    return result;
}
makaPromiseList(urlArr,makeRequest).then((ret)=>{
    console.log(ret)
});

---------------------------------------------------------------------------------------------------------------------------------


http://www.kler.cn/a/6341.html

相关文章:

  • 【Java基础-26.1】Java中的方法重载与方法重写:区别与使用场景
  • Arduino驱动DS18B20测量环境温度
  • 优化 invite_codes 表的 SQL 创建语句
  • WEB UI 创建视图
  • golang , chan学习
  • pyinstaller打包资源文件和ini配置文件怎么放
  • spring七种事务传递机制及其原理
  • 会C#如何学习Python的几个关键点
  • pytorch安装和测试
  • MyBatis
  • 注册谷歌账户教程--解决注册谷歌账户“此电话号码无法用于进行验证”问题--亲测已解决--谷歌账户注册全流程
  • 【面试】Java并发编程面试题
  • XGBoost的简单安装及入门使用
  • Kubuntu(Ubuntu) 22.04安装OBS Studio
  • 简述线程安全问题的原因和解决方案
  • Day913.反向代理和网关是什么关系 -SpringBoot与K8s云原生微服务实践
  • 现在的年轻人真会玩,开发界面都这么时尚,不服老都不行了
  • 第16章_变量、流程控制与游标
  • 记一次weblogic反序列化到内网域控上线
  • 深度探索c++对象模型-31-RTTI与存储位置简介
  • 计算机基本知识扫盲(持续更)
  • 一个令人惊艳的ChatGPT项目,开源了!
  • SpringBoot-核心技术篇
  • STM32G431-基于HAL库(第十四届蓝桥杯嵌入式模拟题2)
  • 【面试】一千万的数据你是怎么查询的?
  • MongoDB - 聚合查询