Ответ 1
Через 5 лет в браузерах произошли большие изменения. Теперь производительность indexOf увеличилась и, безусловно, лучше, чем любая другая альтернативная альтернатива.
Версия Chrome 49.0.2623.87 (64-разрядная версия)
Почему цикл через массив намного быстрее, чем JavaScript native indexOf
? Есть ли ошибка или что-то, что я не учитываю? Я ожидал, что исходные реализации будут быстрее.
For Loop While Loop indexOf
Chrome 10.0 50,948,997 111,272,979 12,807,549
Firefox 3.6 9,308,421 62,184,430 2,089,243
Opera 11.10 11,756,258 49,118,462 2,335,347
Через 5 лет в браузерах произошли большие изменения. Теперь производительность indexOf увеличилась и, безусловно, лучше, чем любая другая альтернативная альтернатива.
Версия Chrome 49.0.2623.87 (64-разрядная версия)
Вероятно, потому что фактическая реализация indexOf делает намного больше, чем просто цикл через массив. Вы можете увидеть внутреннюю реализацию Firefox здесь:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
Есть несколько вещей, которые могут замедлить цикл, который существует для разумных целей:
fromIndex
преобразуется в числоMath.max
вместо тройногоMath.abs
indexOf выполняет кучу проверки и проверки типов, которые игнорируются в цикле for и while.
Здесь алгоритм indexOf:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
Изменить. Мое предположение: indexOf быстрее для больших массивов, потому что он кэширует длину массива перед его прохождением.
Запустите тест еще раз с редактированием, которое я сделал.
Я увеличил размер массива и сделал индекс, который вы ищите, больше. Кажется, что в больших массивах indexOf может быть более быстрым выбором.
РЕДАКТИРОВАТЬ: на основе большего количества тестов indexOf работает быстрее, чем цикл for в версии Safari, который я использую (5.0.3) и медленнее почти во всем остальном.
Возможно, стоит заметить, что если все, что вы пытаетесь сделать, это сохранить список элементов и проверить наличие (например, избегать добавления повторяющихся идентификаторов в массив), было бы гораздо быстрее сохранить OBJECT с ключами, которые отражают каждый идентификатор. Если вы считаете, что я ошибаюсь, сравните следующее с массивом + indexOf. Мы говорим о 181ms для метода объекта против 1 МИНУТ для метода indexOf массива.
var objs = []
var i_uid = {} // method 1
var a_uid = [] // method 2
var total_count = 100000, idLen = 5
var ts, te, cObj = 0
// method 1
ts = new Date()
while (cObj < total_count) {
var u = uid(idLen),
o = {
uid: u,
text: 'something',
created: new Date()
}
if (!i_uid[u]) { // ensure unique uids only
objs.push(o)
i_uid[u] = cObj // current array position as placeholder
cObj++
}
else {
console.log('unique violation [duplicate uid', u, ']')
}
}
te = new Date()
console.log('loaded ' + total_count + ' with object method in', (te - ts), 'ms')
i_uid = {} // free-up
cObj = 0 // reset
objs = [] // reset
// method 2
ts = new Date()
while (cObj < total_count) {
var u = uid(idLen),
o = {
uid: u,
text: 'something',
created: new Date()
}
if (a_uid.indexOf(u) == -1) { // ensure unique uids only
objs.push(o)
a_uid.push(u)
cObj++
}
else {
console.log('unique violation [duplicate uid', u, ']')
}
}
te = new Date()
console.log('loaded ' + total_count + ' with array + indexOf method in', (te - ts), 'ms')
function uid(l) {
var t = '',
p = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
pl = p.length
for (var i = 0; i < l; i++)
t += p.charAt(Math.floor(Math.random() * pl))
return t
}
Мы можем доверять простой в цикл за каждый раз.
Я написал код ниже, чтобы узнать ответ на этот вопрос. Это также runnable.
Он показывает, что простой for loop
является лучшим решением при рассмотрении производительности.
(Код также можно найти на jsfiddle)
console.clear()
let a = []
// populating array data
for (let i = 0; i < 100000; i++) {
a.push(i)
}
let testNum = 90000
let found
let totalMS4ForLoop = 0
let totalMS4IndexOf = 0
let start
let end
// simulating 10000 requests which are come consecutively
for (o = 0; o < 10000; o++) {
start = Date.now()
for (let i = 0; i < a.length; i++) {
if (a[i] == testNum) { found = a[i]; break }
}
end = Date.now()
totalMS4ForLoop += end - start
start = Date.now()
found = a[a.indexOf(testNum)]
end = Date.now()
totalMS4IndexOf += end - start
}
console.log("10000 for-loop executions took total " + totalMS4ForLoop + " ms.")
console.log("10000 indexOf executions took total " + totalMS4IndexOf + " ms.")