JavaScript优化技巧

开发 前端
尝试访问对象的属性时,不仅会在对象上搜索该属性,还会在对象的原型,原型的原型等上搜索该属性,直到找到匹配属性名或原型链的末端。

 作为开发人员,我们一直在寻找让我们的代码更快更好的方法。但在此之前,编写高性能代码需要做三件事:

  • 了解语言及其工作原理
  • 基于用例进行设计
  • 调试!修复!重复

记住这一点

任何傻瓜都可以编写计算机可以理解的代码,优秀的程序员编写人类可以理解的代码。- 丁·福勒

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

延迟

延迟算法将计算延迟到需要执行时才执行,然后生成结果。

  1. const someFn = () => { 
  2.   doSomeOperation() 
  3.   return () => { 
  4.     doExpensiveOperation() 
  5.   } 
  6.  
  7. const t = someArray.filter((x) => checkSomeCondition(x)).map((x) => someFn(x)) 
  8.  
  9. // 现在,如果有需要在执行 
  10. t.map((x) => t()) 

最快的代码是未执行的代码,所以尽量延迟执行。

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

MDN说:

尝试访问对象的属性时,不仅会在对象上搜索该属性,还会在对象的原型,原型的原型等上搜索该属性,直到找到匹配属性名或原型链的末端。

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

所以不要这样:

  1. const name = userResponse.data.user.firstname + userResponse.data.user.lastname 

而是这样做:

  1. const user = userResponse.data.user 
  2. const name = user.firstname + user.lastname 

使用临时变量来保存链接的属性,而不是遍历访问整条链。

使用转译器之前要三思

在上述情况下,userResponse可能不是对象,如果是对象,它的属性 user 也可能不是对象。所以,在获取值时要进行检查:

  1. let name = '' 
  2. if (userResponse) { 
  3.   const data = userResponse.data 
  4.   if (data && data.user) { 
  5.     const user = data.user 
  6.     if (user.firstname) { 
  7.       name += user.firstname 
  8.     } 
  9.     if (user.lastname) { 
  10.       name += user.firstname 
  11.     } 
  12.   } 

这太啰嗦了。代码越多,bug 就越明显。我们能把它缩小吗?当然,可以使用 JS 中可选的链接、解构赋值来优化它。

  1. const user = userResponse?.data?.user 
  2. const { firstname = '', lastname = ''} = user 
  3. const name = firstname + lastname 

是不是很灵活地,简短?不要使用这个要注意,Babel 会按照以下方式进行转换:

  1. 'use strict' 
  2.  
  3. var _userResponse, _userResponse$data 
  4.  
  5. var user = 
  6.   (_userResponse = userResponse) === null || _userResponse === void 0 
  7.     ? void 0 
  8.     : (_userResponse$data = _userResponse.data) === null || 
  9.       _userResponse$data === void 0 
  10.     ? void 0 
  11.     : _userResponse$data.user 
  12. var _user$firstname = user.firstname, 
  13.   firstname = _user$firstname === void 0 ? '' : _user$firstname, 
  14.   _user$lastname = user.lastname, 
  15.   lastname = _user$lastname === void 0 ? '' : _user$lastname 
  16. var name = firstname + lastname 

当使用转译时,确保你选择了一个更适合你的用例的。

了解SMI和堆号

数字很奇怪,ECMAScript将数字标准化为64位浮点值,也称为双精度浮点或Float64表示形式。

如果 JS 引擎以Float64表示形式存储数字,则将导致巨大的性能低下。JS 引擎对数字进行抽象,使其行为与Float64完全匹配。与float64运算相比,JS 引擎执行整数运算的速度要快得多。

有时,我们认为像下面这样写法可读比较好:

  1. const maxWidth = '1000' 
  2. const minWidth = '100' 
  3. const margin = '10' 
  4. getWidth = () => ({ 
  5.   maxWidth: maxWidth - margin * 2, 
  6.   minWidth: minWidth - margin * 2, 
  7. }) 

评估局部变量

如果getWidth函数被多次调用,那么每次调用它时都会计算它的值。上面的计算并不是什么大问题,因此我们不会注意到任何性能影响。

但是总的来说,运行时的求值的数量越少,性能就越好。

  1. // maxWidth - (margin * 2) 
  2. const maxWidth = '980' 
  3. // minWidth - (margin * 2) 
  4. const minWidth = '80' 
  5. const margin = '10' 
  6. getWidth = () => ({ 
  7.   maxWidth, 
  8.   minWidth, 
  9. }) 

使用 Map 而不是 switch/if-else 条件

如果要检查多个条件时,可以使用Map代替 switch/if-else条件。在Map中查找元素的性能比对switch和if-else条件快得多。

  1. switch (day) { 
  2.   case 'monday'
  3.     return 'workday' 
  4.   case 'tuesday'
  5.     return 'workday' 
  6.   case 'wednesday'
  7.     return 'workday' 
  8.   case 'thursday'
  9.     return 'workday' 
  10.   case 'friday'
  11.     return 'workday' 
  12.   case 'saturday'
  13.     return 'funday' 
  14.   case 'sunday'
  15.     return 'funday' 
  16.  
  17. // or this 
  18.  
  19. if ( 
  20.   day === 'monday' || 
  21.   day === 'tuesday' || 
  22.   day === 'wednesday' || 
  23.   day === 'thursday' || 
  24.   day === 'friday' 
  25.   return 'workday' 
  26. else return 'funday' 

上面可以使用 Map 来代替

  1. const m = new Map([ 
  2.     ['monday','workday'], 
  3.     ['tuesday''workday'], 
  4.     ['wednesday''workday'], 
  5.     ['thursday''workday'], 
  6.     ['friday''workday'], 
  7.     ['saturday''funday'], 
  8.     ['sunday''funday'
  9. ]; 
  10.  
  11. return m.get(day); 

if-else 排序

在 React组件中,这种写法还是很常见的。

  1. export default function UserList(props) { 
  2.   const { users } = props 
  3.  
  4.   if (users.length) { 
  5.     return <UserList /> 
  6.   } 
  7.  
  8.   return <EmptyUserList /> 

在这里,我们在没有用户时渲染否则渲染。有大部分人认为,我们首先处理所有空的的情况,然后再处理有数据的情况。对于任何读过它的人来说都更清楚,而且效率更高。也就是说,以下代码比上一个代码更有效。

  1. export default function UserList(props) { 
  2.   const { users } = props 
  3.  
  4.   if (!users.length) { 
  5.     return <EmptyUserList /> 
  6.   } 
  7.  
  8.   // some resource intensive operation 
  9.   return <UserList /> 

当然 users.length 一直有值的话,就使用第一种情况。

类型是你最好的朋友

JavaScript是解释型和编译型语言。为了产生更有效的二进制文件,编译器需要类型信息。但是,作为一种动态类型化的语言会使编译器难以进行。

编译器在编译热代码(多次执行的代码)时进行一些假设并优化代码。编译器花费一些时间来生成此优化的代码。当这些假设失败时,编译器必须丢弃优化的代码,并退回到解释的执行方式。这是耗时且昂贵的。

作者:EthicalAds 译者:前端小智 来源: sendilkumarn

原文:https://sendilkumarn.com/blog/javascript-optimization/

本文转载自微信公众号「 大迁世界 」,可以通过以下二维码关注。转载本文请联系大迁世界公众号。

 

责任编辑:武晓燕 来源: 大迁世界
相关推荐

2022-07-04 08:51:43

条件语句JavaScript

2022-02-25 23:46:54

JavaScript网站开发

2011-09-29 09:50:44

JavaScript

2023-03-19 16:02:33

JavaScrip技巧编程语言

2011-03-25 13:43:54

Cacti优化

2020-06-10 08:37:21

JavaScript重构技巧

2011-07-01 16:05:22

SEO

2011-03-10 10:09:33

LAMP优化

2009-06-16 16:39:49

Hibernate性能

2011-03-09 10:55:33

LAMP优化技巧

2011-05-25 20:53:26

SEO

2023-02-07 08:15:45

PostgreSQLIO技巧

2020-09-29 08:14:46

JavaScript开发代码

2021-08-26 05:04:53

JavaScript调试技巧

2019-01-14 08:06:37

JavaScript

2011-06-14 14:17:23

性能优化系统层次

2022-08-31 12:15:09

JavaScript代码优化

2013-01-21 10:19:50

JavaScript项目管理JS

2012-08-15 09:22:49

JavaScript

2010-08-10 10:17:44

Flex内存
点赞
收藏

51CTO技术栈公众号