我的印象是,大多数ES6功能只是语法糖。但是,当我将MDN上的find polyfill与常规ES6实现进行比较时,速度似乎快了一半。到底能解释这种性能差异的原因是什么,不是全部都一样吗?
请参考下面的代码段以获取基准:
// Find polyfill
function find(obj, predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(obj);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
}
const testArray = ["Hello", "Hi", "Good Morning", "Good Afternoon", "Good Evening", "Good Night"];
// Polyfill benchmark
console.time('findPolyfill');
for (var i = 0; i < 10000; i++) {
find(testArray, (item) => item === "Hello")
}
console.timeEnd('findPolyfill');
// ES6 benchmark
console.time('find ES6');
for (var i = 0; i < 10000; i++) {
testArray.find((item) => item === "Hello");
}
console.timeEnd('find ES6');
答案 0 :(得分:3)
本机版本可以利用内部优化和快捷方式,只要它们不能从外部观察到即可。如果未编译的机器代码,也可能会进行预优化并至少存储为字节码。 (取决于JavaScript引擎。)
相比之下,polyfill正是规范所要求做的非常繁琐的渲染,除非您在紧密循环中运行超过5-10k左右的时间,否则就不太可能选择它来进行积极的优化。引擎。
有趣的是,您的循环设置为运行1万次,因此很可能在引擎对其进行优化之前就停止。否则引擎可能会在途中对其进行优化-进一步延迟结果。例如,对我来说,以下代码使polyfill第一次运行约6毫秒,而第二次和第三次运行约1.1毫秒(Chrome v73中的V8 v7.3)。因此,显然,它在第一次运行时就得到了优化(相反,这可能会减慢运行速度,但显然会加快随后的运行速度。)
// Find polyfill
function find(obj, predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(obj);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
}
const testArray = ["Hello", "Hi", "Good Morning", "Good Afternoon", "Good Evening", "Good Night"];
function testPolyfill() {
// Polyfill benchmark
console.time('findPolyfill');
for (var i = 0; i < 10000; i++) {
find(testArray, (item) => item === "Hello")
}
console.timeEnd('findPolyfill');
}
function testNative() {
// ES6 benchmark
console.time('find ES6');
for (var i = 0; i < 10000; i++) {
testArray.find((item) => item === "Hello");
}
console.timeEnd('find ES6');
}
testPolyfill();
testNative();
testPolyfill();
testNative();
testPolyfill();
testNative();