Javascript Looping Deathmatch
Сегодня утром я прочитал интересную статью, в которой тестировалось несколько различных способов перебрать большой массив чисел, выполнить простое возведение числа в квадрат и записать эти данные обратно в массив результатов. Однако код для тестов оставлял желать лучшего, и я не верю, что это был честный тест.
Я решил провести тесты сам, используя набор данных из 16,105,100
чисел; достаточно длинный набор, чтобы выявить любые различия в алгоритме цикла.
Испытания следующие
Стек: Узел 9.8.0, работающий на MacBook Pro
map.js
const data = require(‘./data’) const results = data.map(i => i * i)
forLoop.js
const data = require(‘./data’) const results = [] for (let i = 0; i < data.length; i++) { results.push(data[i] * data[i]) }
forInLoop.js
const data = require(‘./data’) const results = [] for (const i in data) { results.push(data[i] * data[i]) }
forOfLoop.js
const data = require(‘./data’) const results = [] for (const i of data) { results.push(i * i) }
forEach.js
const data = require(‘./data’) const results = [] data.forEach(i => { results.push(i * i) })
while.js
const data = require('./data') const results = [] let i = 0 while (i < data.length) { results.push(data[i] * data[i]) i++ }
Результаты
Я рассчитал время каждого подхода, используя стандартную функцию unix time
.
time node forLoop
real 0m1.693s user 0m1.413s sys 0m0.298s
time node forInLoop
real 0m5.602s user 0m5.348s sys 0m0.642s
time node forOfLoop
real 0m1.740s user 0m1.463s sys 0m0.297s
time node forEach
real 0m1.863s user 0m1.584s sys 0m0.291s
time node map
real 0m3.330s user 0m3.137s sys 0m0.202s
time node while
real 0m1.959s user 0m1.516s sys 0m0.417s
Совершенно очевидно, что классический for
цикл - самый быстрый, за ним следует цикл стиля for..of
, затем forEach
цикл, затем while
.
Петли map
занимают 5-е место, а петли стиля for in
- худшие с большим отрывом.
В любом случае никто в здравом уме не стал бы использовать цикл for..in
для цикла по массиву, поскольку for..in
предназначен для использования в цикле по свойствам объекта. В идеале вы не должны использовать for..of
, поскольку он предназначен для циклического перебора значений свойств объекта. Это действительно случайно, что, как работают массивы Javascript, индекс считается свойством, а значение - соответствующим значением.
Ни for..in
, ни for..of
также не гарантируют, что они будут зацикливаться в порядке свойств объекта, что делает их непригодными для чего-либо, где вам нужен детерминированный порядок.
Интересно, что forEach
намного быстрее, чем map
, особенно с учетом того, сколько карт используется в современном коде javascript, и оба они работают, вызывая анонимную функцию для значений.
Также интересно, что forIn
использует гораздо больше системного времени, чем другие.
Выводы
Используйте классический for
цикл для максимальной общей скорости или forEach
цикл, если вы предпочитаете более functional
стиль кода.
Вы можете использовать forOf
, если вас не волнует порядок выполнения.
Array.prototype.map
работает медленно, а while
циклы подробны и не дают реальных преимуществ в производительности.
—
Нравится, но не подписчик? Вы можете поддержать автора, присоединившись через davesag.medium.com.