聊一聊我们前端组一起处理的项目优化点
前言
很早一段时间,我们前端组做了一些国外系统的小优化(
集中表现在代码执行速度,系统安全等方面
),故新建一篇文章来记录这次优化的经历。如果本文对您有帮助,烦请大家一键三连哦, 蟹蟹大家~
1. 减小文件体积/网络请求
-
方法一:删除需要预先加载和预先获取的资源,一般使用这种方法
link标签中的
preload
和prefetch
: -
preload
插件用于预加载资源。 即在当前页面加载完成后,立即加载并缓存指定的资源。预加载的资源被认为是当前页面所需的关键资源,因此会优先下载和缓存。 -
prefetch
插件用于预获取资源。 即在当前页面加载完成后,异步地加载并缓存指定的资源,以供将来可能需要的页面使用。预获取的资源被认为是可能会在未来的导航中使用的资源,但不是当前页面所必需的。
`vue.config.js`
module.exports = {
chainWebpack: (config) => {
`删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载`
config.plugins.delete('preload')
`删除需要预先获取(将来的页面)的资源`
config.plugins.delete('prefetch')
}
}
-
方法二:使用
webpack
合并小文件合并
js
代码的意义: -
减少网络请求: 每个文件都需要通过网络进行单独的请求和响应。通过将多个文件合并为一个文件,可以减少页面需要发起的网络请求次数,从而降低延迟和提高加载速度。 -
缓存优化: 合并代码可以提高浏览器缓存的效率。当多个页面共享同一个文件时,浏览器只需要下载并缓存一次该文件,而不是针对每个页面都下载一次。这样可以减少整体的重复下载和提高缓存命中率。 -
减少页面渲染阻塞: 当浏览器下载和执行 js
代码时,它会阻塞页面的渲染过程。通过合并js
代码,可以减少因为多个js
文件的下载和执行而造成的页面渲染阻塞时间,提高页面的响应速度和用户体验。 -
代码优化和压缩: 在合并 js
代码之前,可以对代码进行优化和压缩,去除空格、注释和不必要的代码,从而减少文件大小,并提高代码的执行效率。
`vue.config.js: `
const webpack = require('webpack')
const ENV = process.env.NODE_ENV
module.exports = {
chainWebpack: (config) => {
config.when(ENV === 'production', config => {
config.plugin('webpackOptimize')
.use(
webpack.optimize.LimitChunkCountPlugin,
`限制生成的代码块(chunks)的数量`
[{ maxChunks: 10 }]
)
.use(
webpack.optimize.MinChunkSizePlugin,
`指定代码块的最小字节数`
[{ minChunkSize: 50000 }]
)
})
}
}
-
优化效果截图
优化前的本地环境:
优化后的本地环境(app.js
文件较大,是由于main.js
引入了大量的第三方库):
优化后的线上环境(首先,打包后有对这些文件进行压缩处理,app.js
被压缩至1.24MB
。"inspect": "vue inspect > output.js"
,使用npm run inspect
可以查看webPack
的配置信息。其次,运维都有对这些文件作gzip
压缩处理, 所以体积都减小了很多, 最终app.js
的体积减小至405KB
):
2. 加减乘除
运算集成`big.js`[1],解决js
小数精度问题
-
前提:
当涉及到浮点数计算时,js
中的精度丢失问题, 是由于使用IEEE 754
标准来表示和计算浮点数的方式引起的。这个问题不仅仅在js
中存在,而是在所有使用IEEE 754
标准的编程语言中都会遇到。
IEEE 754
标准定义了两种常见的浮点数表示形式:单精度(32
位)和双精度(64
位)。在 js
中,采用的是双精度表示法,即64
位。
然而,由于二进制和十进制之间的转换存在差异,某些十进制分数无法精确表示为有限位的二进制浮点数。这导致了舍入误差和精度丢失。
-
安装依赖: npm install --save big.js
-
方法封装:
import Big from 'big.js'
export function accFactory(method = 'add') {
return function (...nums) {
`将传入的参数转换为Number类型,并过滤掉不是Number类型的结果`
nums = nums.map(Number).filter((num) => num || num === 0)
`如果过滤后的结果是长度为1的数组,那就返回数组的第一项`
`如果过滤后的结果为空数组,则返回0`
if (nums.length < 2) return nums[0] || 0
`需要为reduce方法赋初值,是因为big.js的运算操作,是基于new Big格式的数字`
`可以将Big对象转换为浮点数,方便后续Number.toFixed()的操作`
return parseFloat(nums.slice(1).reduce((prev, num) => prev[method](num), new Big(nums[0]))) || 0
}
}
`plus、minus、times、div为big.js中的计算方法,分别对应加减乘除这四个运算操作`
`浮点数求和`
export const accAdd = accFactory('plus')
`浮点数相减`
export const accSub = accFactory('minus')
`浮点数相乘`
export const accMul = accFactory('times')
`浮点数相除`
export const accDiv = accFactory('div')
-
测试:
import { accAdd, accSub, accMul, accDiv } from '@/utils/calculate'
mounted() {
this.calTestHandler()
},
methods: {
calTestHandler() {
const operations = [
{ operator: '+', method: accAdd, a: 0.1, b: 0.2 },
{ operator: '-', method: accSub, a: 0.1, b: 0.3 },
{ operator: '*', method: accMul, a: 0.1, b: 0.2 },
{ operator: '/', method: accDiv, a: 0.1, b: 0.3 }
]
operations.forEach((operation) => {
const { operator, method, a, b } = operation
const result = method(a, b)
console.log(`原生js ${operator} 运算:${a} ${operator} ${b}的值是${eval(a + operator + b)}`)
console.log(`big.js ${operator} 运算:${a} ${operator} ${b}的值是${result}`)
})
}
}
结果展示:
3. 使用`bluebird`[2]提升promise
的执行速度
-
前提:
bluebird
是一个流行的Promise
库,用于处理异步操作。它提供了强大的异步编程工具,使得编写和管理异步代码变得更加简单和可靠。
-
Promise
功能增强:bluebird
提供了许多额外的功能和操作,超出了原生Promise
的范围。它支持超时控制、并发控制、错误处理、重试、进度报告和取消等功能。这些功能使得处理复杂的异步控制流变得更加容易。 -
性能优化: bluebird
在性能方面进行了优化,比原生Promise
更快。 它实现了高效的异步调度和内存管理,以提供更快的执行速度和更低的资源消耗。这使得在大规模异步操作的情况下,bluebird
可以提供更高效的性能。 -
错误追踪和调试: bluebird
提供了更好的错误追踪和调试支持。 当使用bluebird
进行异步操作时,它会生成详细的错误堆栈跟踪信息,包括异步操作链的每个步骤。这使得在调试和排查错误时更容易定位问题所在。 -
可互操作性: bluebird
的api
与原生Promise
相似,因此可以与其他使用Promise
的库和代码进行互操作。 这使得在现有的代码基础上,迁移到bluebird
更加容易,并且可以充分利用bluebird
提供的额外功能。
-
安装依赖: npm install --save bluebird
-
方法封装(全局挂载):
import Promise from 'bluebird'
Promise.config({
`确定是否启用警告输出。当设置为true,bluebird会在控制台输出警告,例如不推荐使用的方法或潜在问题`
warnings: false,
`确定是否启用长堆栈跟踪, bluebird会生成详细的异步调用堆栈信息,包括Promise链中的每个步骤。`
`这对于调试和错误追踪非常有用, 但启用长堆栈跟踪,可能会对性能产生一些影响`
longStackTraces: false,
`确定是否启用取消功能。当设置为true时,bluebird允许取消异步操作。`
`取消一个Promise将导致其相关的操作被中断或忽略,有助于优化资源使用和控制异步流程。`
cancellation: true,
`确定是否启用性能监视。当设置为true时,bluebird可以收集异步操作的性能数据,例如执行时间、调用次数等。`
`这对于分析和优化异步操作的性能非常有用。`
monitoring: true,
`确定是否启用异步挂钩。异步挂钩是node.js提供的一种机制,可以在异步操作的不同阶段执行回调函数。`
`当设置为true时,bluebird将使用异步挂钩来跟踪和管理异步操作`
asyncHooks: false
})
window.bluePromise = Promise
`main.js`
import bluebird from '@/utils/bluebird'
-
测试
mounted() {
this.proTestHandler()
},
methods: {
async proTestHandler() {
const promises = []
const bluebirds = []
const promiseList = (promise, count, arr) => {
for (let i = 0; i < count; i++) {
arr.push(new promise((resolve) => resolve(i)))
}
}
const generatePromises = () => {
promiseList(Promise, 1000000, promises)
promiseList(bluePromise, 1000000, bluebirds)
}
generatePromises()
console.log('promise')
console.time()
await Promise.all(promises)
console.timeEnd()
console.log('bluebirds')
console.time()
await bluePromise.all(bluebirds)
console.timeEnd()
}
}
结果展示
4. 使用`hashids`[3]加密路由id
-
前提:
在网址上应用hashids
有以下4
点重要意义:
-
加密隐藏真实id: 在某些情况下,你可能希望隐藏网址中的真实 id
,以增加安全性和防止直接暴露敏感信息。使用hashids
,可以将真实的数字id
转换为短字符串,并在网址中使用该短字符串代替原始id
。这样,外部用户只能看到短字符串,而无法直接推断出真实的id
值。 -
可读性和美观性: 长的数字 id
在网址中可能显得冗长和难以理解。使用hashids
将其转换为短字符串,可以大大提升网址的可读性和美观性。短字符串通常包含字母和数字的组合,更易于记忆和分享。 -
防止猜测和遍历: 使用连续的数字 id
在网址中可能导致猜测和遍历的风险,因为攻击者可以通过递增id
来尝试访问和暴露数据。通过使用hashids
生成的短字符串作为id
,可以有效地防止这种攻击。由于短字符串是随机生成的,攻击者无法根据短字符串推断出下一个id
。 -
URL缩短和分享: hashids
生成的短字符串可以用作url
缩短服务的替代方案。你可以将长的url
转换为短字符串,并在分享时使用该短字符串。这对于限制字符数、简化链接以及在社交媒体和短信中共享链接都非常有用。
-
安装依赖: npm install --save hashids
-
方法封装(全局挂载):
`短码方法封装:`
import Hashids from 'hashids'
const hashids = new Hashids(
`盐值是一个可选的字符串参数,用于增加生成的短码的唯一性和安全性。每个不同的盐值将产生不同的短码序列,`
`可以将盐值视为项目的名称或标识符。如果不提供盐值,则默认为一个空字符串。`
'toadditWeb',
`是一个可选的整数参数,用于指定生成的短码的最小长度。如果生成的短码长度小于指定的最小长度,`
`hashids会自动填充短码以达到最小长度。这只是一个最小长度的限制,实际生成的短码长度可能更长。`
`如果不提供最小长度,则默认为0,即没有最小长度限制。`
8,
`字母表是一个可选的字符串参数,用于定义生成短码时使用的字符集。该字符串包含所有可用于生成短码的字符。`
`通常,字母表中应包含一组不容易混淆的字符,以避免生成的短码产生歧义。如果不提供字母表,则默认为`
`"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"`。
)
`短码封装`
export function encode(val) {
return hashids.encode(val)
}
`短码解析`
export function decode(val) {
return hashids.decode(val)[0]
}
`glboal.js: 全局注册`
import { encode, decode } from '@/utils/hashids'
export default {
install(Vue) {
Vue.prototype.$encode = window.$encode = (data) => encode(data)
Vue.prototype.$decode = window.$decode = (data) => decode(data)
}
}
`在main.js中挂载:`
import Vue from 'vue'
import App from './App'
import globalConst from '@/commons/globalConst'
Vue.use(globalConst)
new Vue({
el: '#app',
router,
store,
render: (h) => h(App)
})
-
测试:
mounted() {
this.hashTestHandler()
},
methods: {
hashTestHandler() {
const testId = 18
const encode = $encode(testId)
console.log(`hashids编码前: ${testId}`)
console.log(`hashids编码: ${encode}`)
console.log(`hashids解码: ${$decode(encode)}`)
}
}
结果展示(在同一个盐值下,不管页面是否刷新,编码结果都不会改变
):
5. 登陆时使用`行为验证码`[4]
-
前提:
登陆时使用行为验证码
有以下5
点重要意义:
-
增强安全性: 传统的验证码可以被自动化的机器人或恶意程序轻易地破解或绕过。而 行为验证码
通过分析用户的行为模式,可以更准确地识别是否是真实用户,从而提高安全性,防止恶意活动和机器人攻击。 -
用户友好性: 相比于传统的验证码, 行为验证码
通常对用户来说更加友好和便捷。用户无需输入复杂的文本或解析模糊的图像,而是通过正常的交互行为完成验证,例如简单的滑动、点击、拖拽等操作。 -
无感知验证: 行为验证码
可以在用户进行正常的操作过程中进行验证,几乎无需用户额外的干预或注意。这样可以减少对用户的干扰和阻碍,提升用户体验。 -
自适应性: 行为验证码
可以根据用户的行为模式自适应地进行验证。它可以根据用户的设备、IP地址、浏览器指纹、鼠标移动轨迹等因素来综合评估用户的真实性,从而提高准确性和安全性。 -
防止数据滥用: 行为验证码
可以用于防止恶意用户或攻击者滥用系统或服务。通过分析用户的行为模式和交互方式,可以及时识别和阻止异常行为,保护系统和数据的安全。
前端参考文档:https://github.com/Yunlingfly/vue-captcha/tree/master
最终效果:
作者:沐浴在曙光下的贰货道士
链接:https://juejin.cn/post/7264440609129119804
来源:稀土掘金