Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在数组中循环要比JavaScript快得多;是本地的'indexOf'?_Javascript_Performance - Fatal编程技术网

为什么在数组中循环要比JavaScript快得多;是本地的'indexOf'?

为什么在数组中循环要比JavaScript快得多;是本地的'indexOf'?,javascript,performance,Javascript,Performance,为什么在数组中循环要比JavaScript的原生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

为什么在数组中循环要比JavaScript的原生
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   

可能是因为实际的indexOf实现所做的远远不止是在数组中循环。您可以在这里看到它的Firefox内部实现:

出于理智的考虑,有几种方法可以减缓循环的速度:

  • 正在将数组重新转换为对象
  • 正在将索引中的
    转换为数字
  • 他们用的是
    Math.max
    而不是三元数
  • 他们正在使用
    Math.abs

indexOf执行一系列for循环和while循环忽略的类型检查和验证

以下是indexOf算法:


编辑:我猜indexOf对于大型数组更快,因为它在循环遍历数组之前会缓存数组的长度。

使用我所做的编辑再运行一次测试

我已经增加了数组的大小,并且使您搜索的索引也变大了。在大型阵列中,indexOf可能是一个更快的选择


编辑:基于更多的测试,在我使用的Safari版本(5.0.3)中,indexOf似乎比for循环运行得更快,而在其他方面运行得更慢。五年后,浏览器发生了很多变化。现在,indexOf的性能有所提高,并且肯定比任何其他定制替代方案都要好


Chrome版本49.0.2623.87(64位)

值得注意的是,如果您只想保存一个项目列表并检查是否存在(例如,避免向数组中添加重复ID),那么保存一个包含反映每个ID的键的对象会快得多。如果您认为我错了,请将以下内容与数组+索引进行比较。我们谈论的对象方法是181ms,而数组indexOf方法是1分钟

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
}
var objs=[]
var i_uid={}//方法1
var a_uid=[]//方法2
var总计数=100000,idLen=5
变量ts,te,cObj=0
//方法1
ts=新日期()
而(cObj<总计数){
var u=uid(idLen),
o={
uid:u,
文字:“某物”,
创建日期:新日期()
}
如果(!i_uid[u]){//请确保只有唯一的uid
对象推送(o)
i_uid[u]=cObj//当前数组位置作为占位符
眼镜蛇++
}
否则{
console.log('唯一冲突[duplicate uid',u',]')
}
}
te=新日期()
log('loaded'+total_count+',对象方法位于',(te-ts),'ms')
i_uid={}//释放
cObj=0//reset
objs=[]//重置
//方法2
ts=新日期()
而(cObj<总计数){
var u=uid(idLen),
o={
uid:u,
文字:“某物”,
创建日期:新日期()
}
如果(a_uid.indexOf(u)==-1){//请确保只有唯一的uid
对象推送(o)
油推(u)
眼镜蛇++
}
否则{
console.log('唯一冲突[duplicate uid',u',]')
}
}
te=新日期()
log('loaded'+total_count+'with array+indexOf method in',(te-ts),'ms'))
函数uid(l){
变量t=“”,
p='ABCDEFGHIJKLMNOPQRSTUVXYZABCDFGHIJKLMNOPQRSTUVXYZ0123456789',
pl=p.长度
对于(变量i=0;i
我们每次都可以信任一个简单的for循环

我写了下面的代码来发现这个问题的答案。它也是可运行的。 它表明,在考虑性能时,普通
for loop
是最佳解决方案

(该代码也可在上找到)

console.clear()
设a=[]
//填充数组数据
for(设i=0;i<100000;i++){
a、 推送(一)
}
设testNum=90000
发现
设totalMS4ForLoop=0
设totalMS4IndexOf=0
让我们开始吧
结束
//模拟连续发出的10000个请求
对于(o=0;o<10000;o++){
开始=日期。现在()
for(设i=0;ilog(“10000次indexOf执行总共花费了”+totalMS4IndexOf+“ms.”)
好的,看看这里的其他基准测试,我对大多数开发人员进行基准测试的方式感到挠头

抱歉,但这样做会导致可怕的错误结论,所以我必须稍微做一点,并对提供的答案发表评论

这里的其他基准有什么问题 在一个永远不会改变的数组中,测量在何处找到777元素,总是导致索引117,出于明显的原因,这似乎是不合适的,我很难解释为什么。你不能从这样一个过于具体的基准中合理地推断出任何东西!我唯一能想到的类比是对一个人进行人类学研究,然后将研究结果称为对此人所在国家整个文化的概括概括。其他基准也没有好多少

更糟糕的是:被接受的答案是一个没有链接到所使用的基准的图像,因此我们无法控制该基准的代码是否正确(我希望这是一个jsperf链接的屏幕截图,该链接最初在问题中,后来为了支持新的jsben.ch链接而被编辑掉)。这甚至不是对原始问题的解释:为什么一个表现比另一个好(一开始就有高度争议的说法)

首先,您应该知道-有些可能会给某些类型的测量增加重大错误