发布于 2026-01-06 6 阅读
0

加速 JavaScript 执行 🚀🚀🚀 避免使用惰性求值 注意对象链式调用 使用转译器前请三思 了解 SMI 和堆编号 求值局部变量 使用 Map 代替 switch / if-else 条件语句 if-else 语句的顺序 类型是你最好的朋友 其他

加快 JavaScript 执行速度🚀🚀🚀

偷懒

注意对象链式调用

使用转译器前请三思

了解 SMI 和堆编号

评估局部变量

使用 Map 代替 switch / if-else 条件语句

if-else 排序

性格类型是你最好的朋友

其他的

作为开发人员,我们总是想方设法让我们的代码运行得更快、更好。

但在此之前,编写高性能代码需要做到三件事:

  1. 了解这门语言及其运作方式。
  2. 基于用例的设计
  3. 调试!修复!重复!

记住这一点,

任何傻瓜都能写出计算机能理解的代码。优秀的程序员写出的代码,人类也能理解。——马丁·福勒

让我们来看看如何让 JavaScript 代码运行得更快。

偷懒

惰性算法会将计算推迟到需要执行时才执行,然后再产生结果。

const someFn = () => {
    doSomeOperation();
    return () => { 
      doExpensiveOperation();
    };
}


const t = someArray
             .filter(x => checkSomeCondition(x))
             .map(x => someFn(x)); 

// Now execute the expensive operation only when needed.
t.map(x => t());
Enter fullscreen mode Exit fullscreen mode

简而言之:最快的代码就是不执行的代码。所以,尽量延迟执行代码。

注意对象链式调用

JavaScript 使用原型继承。JavaScript 世界中的所有对象都是Object的实例。

MDN表示,

当尝试访问对象的属性时,不仅会在该对象上查找该属性,还会在该对象的原型上查找,在原型的原型上查找,依此类推,直到找到名称匹配的属性或到达原型链的末尾。

对于每个属性,JavaScript 引擎都必须遍历整个对象链,直到找到匹配项。如果使用不当,这会消耗大量资源并严重影响应用程序性能。

所以不要这样做

const name = userResponse.data.user.firstname + userResponse.data.user.lastname;
Enter fullscreen mode Exit fullscreen mode

而是这样做

const user = userResponse.data.user;
const name = user.firstname + user.lastname;
Enter fullscreen mode Exit fullscreen mode

简而言之:使用临时变量来保存链式属性,而不是重复遍历整个链式结构。

使用转译器前请三思

在上述情况下,该对象userResponse可能具有也可能不具有该data对象。该data对象可能具有也可能不具有该user属性。

我们可以像这样检查获取值的过程

let name = '';
if (userResponse) {
    const data = userResponse.data;
    if (data && data.user) {
        const user = data.user;
        if (user.firstname) {
             name += user.firstname;
        }
        if (user.lastname) {
             name += user.firstname;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

这段代码确实有点冗长。代码越多,出错的可能性就越大。我们能不能精简一下呢?当然可以,JavaScript 有可选链式调用解构赋值等机制来简化代码。

const user = userResponse?.data?.user;
const {firstname = '', lastname = ''} = user;
const name = firstname + lastname;
Enter fullscreen mode Exit fullscreen mode

是不是很酷炫?很现代?但是使用这类东西时要小心,Babel 会将它们转译成如下形式:

"use strict";

var _userResponse, _userResponse$data;

var user = (_userResponse = userResponse) === null || _userResponse === void 0 ? void 0 : (_userResponse$data = _userResponse.data) === null || _userResponse$data === void 0 ? void 0 : _userResponse$data.user;
var _user$firstname = user.firstname,
    firstname = _user$firstname === void 0 ? '' : _user$firstname,
    _user$lastname = user.lastname,
    lastname = _user$lastname === void 0 ? '' : _user$lastname;
var name = firstname + lastname;
Enter fullscreen mode Exit fullscreen mode

简而言之:使用转译时,请确保选择最适合您用例的转译方式。

了解 SMI 和堆编号

数字很​​奇妙。ECMAScript 将数字标准化为 64 位浮点值,也称为 64 位浮点double precision floating-point表示Float64法。

如果 JavaScript 引擎以 Float64 格式存储数字,将会导致严重的性能损失。JavaScript 引擎对数字进行抽象,使其行为与 Float64 完全一致。与 Float64 运算相比,JavaScript 引擎执行整数运算的速度要快得多float64

更多详情请见此处

TL;DR:尽可能使用小整数(SMI)。

评估局部变量

有时,人们认为提供这样的值是可行的,

const maxWidth = '1000';
const minWidth = '100';
const margin = '10';
getWidth = () => ({
    maxWidth: maxWidth - (margin * 2),
    minWidth: minWidth - (margin * 2),
});
Enter fullscreen mode Exit fullscreen mode

如果getWidth函数被多次调用,每次调用时都会重新计算该值。上述计算量不大,因此不会对性能造成任何影响。

但总的来说,运行时评估越少,性能越好。

// maxWidth - (margin * 2)
const maxWidth = '980';
// minWidth - (margin * 2)
const minWidth = '80';
const margin = '10';
getWidth = () => ({
    maxWidth,
    minWidth
});
Enter fullscreen mode Exit fullscreen mode

运行时评估次数越少,性能越好。

使用 Map 代替 switch / if-else 条件语句

当你想检查多个条件时,请使用 `a`Map而不是switch`/`if-else条件。在 `a` 中查找元素的性能map高于评估 ` switchand`if-else条件。

switch (day) {
    case 'monday' : return 'workday';
    case 'tuesday' : return 'workday';
    case 'wednesday' : return 'workday';
    case 'thursday' : return 'workday';
    case 'friday' : return 'workday';
    case 'saturday' : return 'funday';
    case 'sunday' : return 'funday';
}

// or this

if (day === 'monday' || day === 'tuesday' || day === 'wednesday' || day === 'thursday' || day === 'friday') return 'workday';
else return 'funday';
Enter fullscreen mode Exit fullscreen mode

两者都用这个,

const m = new Map([
    ['monday','workday'],
    ['tuesday', 'workday'],
    ['wednesday', 'workday'],
    ['thursday', 'workday'],
    ['friday', 'workday'],
    ['saturday', 'funday'],
    ['sunday', 'funday']
];

return m.get(day);
Enter fullscreen mode Exit fullscreen mode

TL;DR;使用 Map 代替 switch/if-else 条件语句

if-else 排序

例如,如果您正在编写 React 组件,遵循这种模式非常常见。

export default function UserList(props) {
    const {users} = props;

    if (users.length) {
        // some resource intensive operation.
        return <UserList />;
    }

    return <EmptyUserList />;
}
Enter fullscreen mode Exit fullscreen mode

这里,我们会<EmptyUserList />在没有用户时渲染页面<UserList />。我看到有人认为我们应该先处理所有负面情况,然后再处理正面情况。他们经常提出这样的论点:这种写法更清晰易懂,效率也更高。也就是说,下面的代码比之前的代码效率更高。

export default function UserList(props) {
    const {users} = props;

    if (!users.length) {
       return <EmptyUserList />;
    }

    // some resource intensive operation
    return <UserList />;
}
Enter fullscreen mode Exit fullscreen mode

但如果条件users.length始终为真呢?先使用这个条件,然后再使用否定条件。

简而言之:在设计if-else条件时,应按减少评估条件数量的顺序排列。

性格类型是你最好的朋友

JavaScript 既是解释型语言又是编译型语言。编译器为了生成更高效的二进制文件,需要类型信息。但由于 JavaScript 是一种动态类型语言,这给编译器带来了困难。

编译器在编译高频代码(即执行次数较多的代码)时,会做出一些假设并进行优化。编译器需要花费一些时间来生成这些优化后的代码。当这些假设不成立时,编译器就必须丢弃优化后的代码,并回退到解释执行的方式。这既耗时又费力。

简而言之:始终使用单态类型。

其他的

尽量避免使用递归,虽然递归很棒,代码也更易读,但也会降低性能。

尽可能地使用记忆化功能。

有时,位运算符和一元运算符能略微提升性能。但当性能预算非常紧张时,它们才真正发挥作用。


讨论区🐦 Twitter // 💻 GitHub // ✍️ 博客

如果你喜欢这篇文章,请点赞或留言。❤️


文章来源:https://dev.to/sendilkumarn/boost-your-javascript-performance-2fbl