【发布时间】:2017-05-23 21:11:21
【问题描述】:
正如您可以在下面的代码中查看的那样,通过在属性名称前加上 + 或 - 来定义排序顺序会导致排序速度大大降低。任何想法为什么?
默认排序(值):5.84ms
升序(+值):58.59ms
降序排序(-value):49.28ms
value 和 +value 之间存在差异(两者都返回完全相同的排序顺序)让我非常困惑。
let arr = []
for (let i = 0; i < 10000; ++i) {
arr.push({ _id: 'doc' + i, value: Math.random(), k: i % 20 })
}
function sort (...keys) {
let data = {}
data.sort = []
keys.forEach(key => {
const newKey = key.replace(/(\-|\+)/g, '')
const order = key[0] === '-' ? -1 : 1
data.sort.push({
key: newKey,
order: order
})
})
return data
}
function compare (sortData, a, b) {
for (let i = 0; i < sortData.length; ++i) {
const data = sortData[i]
const _a = a[data.key]
const _b = b[data.key]
if (_a !== _b) return _a > _b ? data.order : -data.order
}
return 0
}
function exec (data) {
let r = arr.slice()
if (data.sort) {
r.sort((a, b) => {
let r = compare(data.sort, a, b)
return r
})
}
return r
}
function time (f) {
let start = performance.now()
f()
return performance.now() - start
}
function test (f, n) {
let total = 0
for (let i = 0; i < n; ++i) total += time(f)
return total / n
}
const q1 = sort('value')
const q2 = sort('+value')
const q3 = sort('-value')
const sortDefault = () => exec(q1)
const sortAsc = () => exec(q2)
const sortDesc = () => exec(q3)
console.log(' Default Sort (value):', test(sortDefault, 10).toFixed(2) + 'ms')
console.log(' Ascending Sort (+value):', test(sortAsc, 10).toFixed(2) + 'ms')
console.log('Descending Sort (-value):', test(sortDesc, 10).toFixed(2) + 'ms')
【问题讨论】:
-
不确定性能差异,但这是在 JS 中编写比较器的一种奇怪方式。编写一个返回然后传递给
Array.prototype.sort的函数会更常见。 -
对我来说差不多是同一时间:
Default Sort (value): 6.60ms Ascending Sort (+value): 9.45ms Descending Sort (-value): 7.39ms -
奇怪的是,我在 Firefox 中也遇到了同样的困难时间,但 IE/Edge/Chrome/NodeJS 都导致时间增加。
-
Chrome 似乎是最大的不同。只是一个猜测,但我认为这与字段访问中的破坏优化有关,他们能够静态确定
"value"永远不会被key.replace(/(\-|\+)/g, '')更改,因此他们能够使用他们的低级类表示但与其他人一样,它默认为对象的哈希表表示。当引擎无法静态确定表达式的值时,通过[...]访问键可以做到这一点。 -
如果这对性能至关重要,那么找到一种方法而不是将顺序编码到密钥中可能不是一个坏主意。
标签: javascript node.js sorting