【译】JavaScript 中的性能和可读性

原文:Performance vs Readability算法

JavaScript 已经发展成为一种更易读的语言。毫无疑问,这对这门语言的发展是毫无害处的。数组

而软件开发始终是在一个团队不断变化的动态环境中的,这意味着现有代码对于团队新手来讲是须要可读的。可是,可读性必须是以性能为代价的吗?在哪里划分性能和可读性之间的界限?何时牺牲一个来追求另外一个?是否须要在某些时候牺牲其中一个?浏览器

在下面,笔者准备回答上述的一些问题?或者帮你们试图一块儿去理解。服务器

还有一个问题是,你们尝试在代码中实现高性能的缘由是显而易见的,可是,为何也如此沉迷于可读性呢?函数

一样的问题,不一样的解决方案

下面,咱们来看一个很常见的问题:工具

给定一组无序数字,返回一个新数组,为每一个值加 1 并对其进行排序,同时不改变原始数组的数据。oop

var numbers = [2, 4, 12, 6, 8, 29, 5, 10, 87, 11, 7];性能

function process(arr) { let newArr = arr.slice(); newArr[0]++; for (let i = 1; i < newArr.length; i++) { const current = newArr[i] + 1; let leftIndex = i - 1;测试

while (leftIndex >= 0 && newArr[leftIndex] > current) {
        newArr[leftIndex + 1] = newArr[leftIndex];
        leftIndex = leftIndex - 1;
    }
    newArr[leftIndex + 1] = current;
}
return newArr;
复制代码

}大数据

const newArray = process(numbers);

(笔者使用插入排序,只是由于它比较容易实现)

这个代码示例并非真正可读的,可是,性能更高,比可读的 ES6 代码更高效。例如这个:

const process = (arr) => arr .map(num => num + 1) .sort((a, b) => a - b);

const newArray = process(numbers);

事实上,第一个代码示例比第二个代码示例快约 75%,即便第二个代码示例更具可读性,甚至能够简化为单行代码:

const newArray = numbers.map(num => num + 1).sort((a, b) => a - b);

或者使用辅助函数拆分以得到更好的可读性:

const addOne = (n) => n + 1; const asc = (a, b) => a - b; const newArray = numbers.map(addOne).sort(asc);

很明显,ES6 示例(不管采用何种方法)都更具可读性,使代码更容易理解。 采用可读代码,团队能够更快地向项目中引入新的开发人员,也能够更轻松地共享代码,并使其更易于维护。

考虑到所有因素,在大多数状况下,性能变得并不是那么重要。这就是 ES6 以这种方式发展的缘由。

两种方法之间的最终比较:

在这一点上,你可能会问:“还有什么不那么高效,但更具可读性的代码?

好吧,下面让咱们一块儿看看一些主要的用例。

Spread 语法 vs Object.assign()

来看下面这个简单问题:

复制对象并向副本添加新属性

解决方案:

const params = {...}; // filled Object

// ES6 - Spread syntax var copy1 = { a: 2, ...params };

// Object.assign() var copy2 = Object.assign({}, { a: 2 }, params);

这两种方法均可以完成这项工做,但** Spread 语法更易读,即便速度慢约 54%**。

关于循环和 Reduce

问题:

求和数组的全部值

解决方案,从经典的 for ... loop 开始:

const numbers = [2, 4, 12, 6, 8, 29, 5, 10, 87, 11, 7];

function arraySum(arr) { let sum = 0; for (let i = 0; i < arr.length; i++) { sum += arr[i] } return sum; }

const sumOfNumbers = arraySum(numbers);

如今使用 Reduce:

const numbers = [2, 4, 12, 6, 8, 29, 5, 10, 87, 11, 7];

const add = (a, b) => a + b; const arraySum = (arr) => arr.reduce(add);

const sumOfNumbers = arraySum(numbers);

在这种状况下,从性能的角度来看,下降是很是明显的,速度要慢约 96%!

For vs While vs Do while

差别很是不明显,可是,若是非要有结论的话,请继续使用经典的 for 循环。

何时用什么

哇! 如今不少可读性的编码方式很受欢迎。笔者正在使用 spread 语法,reduce 等等来完成全部逻辑!

这里的情绪有点使人沮丧,他们承诺可读性而没有性能成本的!但事实并不是如此。

这里不要惶恐不安,来分析下当前的状况。 那么,“我何时用?

上述问题的答案比实际预期的要容易:取决于项目状况

回到第一个例子,若是必须:复制,添加和排序中小数据量的数组或对象,那么为了可读性,咱们将使用 ES6 武器库中的全部可用玩具。

事实上,几乎全部代码均可以在编写时將重点放在可读性而不是性能上,但具体执行要取决于项目状况。

咱们试着把这些状况放在列表中来展现。

什么时候优先考虑可读性

  • 当咱们处理的数据量不是很大时
  • 当应用程序在速度,负载等方面正确运行时
  • 在具备许多项目新手的动态环境中工做时
  • 在编写人们可能必须阅读和理解的库或插件时

什么时候优先考虑性能

  • 在处理大数据时
  • 当应用程序运行缓慢或存在其余性能问题时
  • 当项目意图可扩展时
  • 在我的项目中工做时,可使用本身想要的高性能代码

所以,若是咱们处理大数据,请避免在专门处理该对象或数组的代码部分中使用 reduce,filter,map,spread 语法等。

结论

咱们应该退后一步来看,分析选选择的方式是否让项目和用例变得更方便,而不是伏先选择最新和最酷的东西。

毫无疑问,新的 ES6 功能是让人幸福的,在平常JavaScript 编码中产生不少乐趣,但若是正在努力提升性能,或者处理大量数据,这对应该从新考虑正在使用的那些工具。

对于繁重的工做,笔者会寻求一个不太可读的代码,但性能更高。💪

对于大量数据,笔者会去研究和实现最适合该任务的高性能算法。 💪👓

对于全部其余状况,笔者选择了 ES6 这个可读的小可爱 !!❤

声明

在不一样的浏览器、操做系统和服务器工做负载的情形下,此帖子中显示的测试结果可能略有不一样。