Skip to content

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

大厂技术  高级前端  Node 进阶

点击上方 程序员成长指北,关注公众号

回复 1,加入高级 Node 交流群

前言

很早一段时间,我们前端组做了一些国外系统的小优化 (集中表现在代码执行速度,系统安全等方面),故新建一篇文章来记录这次优化的经历。如果本文对您有帮助,烦请大家一键三连哦, 蟹蟹大家~

  1. 减小文件体积 / 网络请求

  • 方法一:删除需要预先加载和预先获取的资源,一般使用这种方法

    link 标签中的preloadprefetch

  1. preload插件用于预加载资源。 即在当前页面加载完成后,立即加载并缓存指定的资源。预加载的资源被认为是当前页面所需的关键资源,因此会优先下载和缓存。

  2. prefetch插件用于预获取资源。 即在当前页面加载完成后,异步地加载并缓存指定的资源,以供将来可能需要的页面使用。预获取的资源被认为是可能会在未来的导航中使用的资源,但不是当前页面所必需的。

`vue.config.js`module.exports = {  chainWebpack: (config) => {    `删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载`    config.plugins.delete('preload')      `删除需要预先获取(将来的页面)的资源`    config.plugins.delete('prefetch')  }}
  • 方法二:使用webpack合并小文件

    合并js代码的意义:

  1. 减少网络请求: 每个文件都需要通过网络进行单独的请求和响应。通过将多个文件合并为一个文件,可以减少页面需要发起的网络请求次数,从而降低延迟和提高加载速度。

  2. 缓存优化: 合并代码可以提高浏览器缓存的效率。当多个页面共享同一个文件时,浏览器只需要下载并缓存一次该文件,而不是针对每个页面都下载一次。这样可以减少整体的重复下载和提高缓存命中率。

  3. 减少页面渲染阻塞: 当浏览器下载和执行js代码时,它会阻塞页面的渲染过程。通过合并js代码,可以减少因为多个js文件的下载和执行而造成的页面渲染阻塞时间,提高页面的响应速度和用户体验。

  4. 代码优化和压缩: 在合并js代码之前,可以对代码进行优化和压缩,去除空格、注释和不必要的代码,从而减少文件大小,并提高代码的执行效率。

`vue.config.js: `const webpack = require('webpack')const ENV = process.env.NODE_ENVmodule.exports = {  chainWebpack: (config) => {    config.when(ENV === 'production', config => {      config.plugin('webpackOptimize')      .use(        webpack.optimize.LimitChunkCountPlugin,         `限制生成的代码块(chunks)的数量`        [{ maxChunks: 10 }]      )      .use(        webpack.optimize.MinChunkSizePlugin,         `指定代码块的最小字节数`        [{ minChunkSize: 50000 }]      )    })  }}
  • 优化效果截图

优化前的本地环境:

image.png

优化后的本地环境 (app.js文件较大,是由于main.js引入了大量的第三方库):

优化后的线上环境 (首先,打包后有对这些文件进行压缩处理,app.js被压缩至1.24MB"inspect": "vue inspect > output.js",使用npm run inspect可以查看webPack的配置信息。其次,运维都有对这些文件作gzip压缩处理, 所以体积都减小了很多, 最终app.js的体积减小至405KB):

image.png

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}`)    })  }}

结果展示:

image.png

  1. 使用 bluebird[2] 提升promise的执行速度

  • 前提:

bluebird是一个流行的Promise库,用于处理异步操作。它提供了强大的异步编程工具,使得编写和管理异步代码变得更加简单和可靠。

  1. Promise功能增强: bluebird提供了许多额外的功能和操作,超出了原生Promise的范围。它支持超时控制、并发控制、错误处理、重试、进度报告和取消等功能。这些功能使得处理复杂的异步控制流变得更加容易。

  2. 性能优化:bluebird在性能方面进行了优化,比原生Promise更快。 它实现了高效的异步调度和内存管理,以提供更快的执行速度和更低的资源消耗。这使得在大规模异步操作的情况下,bluebird可以提供更高效的性能。

  3. 错误追踪和调试:bluebird提供了更好的错误追踪和调试支持。 当使用bluebird进行异步操作时,它会生成详细的错误堆栈跟踪信息,包括异步操作链的每个步骤。这使得在调试和排查错误时更容易定位问题所在。

  4. 可互操作性:bluebirdapi与原生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()  }}

结果展示

image.png

  1. 使用 hashids[3] 加密路由id

  • 前提:

在网址上应用hashids有以下4点重要意义:

  1. 加密隐藏真实 id: 在某些情况下,你可能希望隐藏网址中的真实id,以增加安全性和防止直接暴露敏感信息。使用hashids,可以将真实的数字id转换为短字符串,并在网址中使用该短字符串代替原始id。这样,外部用户只能看到短字符串,而无法直接推断出真实的id值。

  2. 可读性和美观性: 长的数字id在网址中可能显得冗长和难以理解。使用hashids将其转换为短字符串,可以大大提升网址的可读性和美观性。短字符串通常包含字母和数字的组合,更易于记忆和分享。

  3. 防止猜测和遍历: 使用连续的数字id在网址中可能导致猜测和遍历的风险,因为攻击者可以通过递增id来尝试访问和暴露数据。通过使用hashids生成的短字符串作为id,可以有效地防止这种攻击。由于短字符串是随机生成的,攻击者无法根据短字符串推断出下一个id

  4. 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)}`)  }}

结果展示 (在同一个盐值下,不管页面是否刷新,编码结果都不会改变):

image.png

  1. 登陆时使用 行为验证码[4]

  • 前提:

登陆时使用行为验证码有以下5点重要意义:

  1. 增强安全性: 传统的验证码可以被自动化的机器人或恶意程序轻易地破解或绕过。而行为验证码通过分析用户的行为模式,可以更准确地识别是否是真实用户,从而提高安全性,防止恶意活动和机器人攻击。

  2. 用户友好性: 相比于传统的验证码,行为验证码通常对用户来说更加友好和便捷。用户无需输入复杂的文本或解析模糊的图像,而是通过正常的交互行为完成验证,例如简单的滑动、点击、拖拽等操作。

  3. 无感知验证: 行为验证码可以在用户进行正常的操作过程中进行验证,几乎无需用户额外的干预或注意。这样可以减少对用户的干扰和阻碍,提升用户体验。

  4. 自适应性: 行为验证码可以根据用户的行为模式自适应地进行验证。它可以根据用户的设备、IP 地址、浏览器指纹、鼠标移动轨迹等因素来综合评估用户的真实性,从而提高准确性和安全性。

  5. 防止数据滥用: 行为验证码可以用于防止恶意用户或攻击者滥用系统或服务。通过分析用户的行为模式和交互方式,可以及时识别和阻止异常行为,保护系统和数据的安全。

前端参考文档:https://github.com/Yunlingfly/vue-captcha/tree/master

最终效果:

image.png

作者:沐浴在曙光下的贰货道士

链接:https://juejin.cn/post/7264440609129119804

来源:稀土掘金

结语

Node 社群

我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

   “分享、点赞、在看” 支持一下