为什么Function.prototype.bind很慢?
Why is Function.prototype.bind slow?
当将这个基准测试与chrome 16和opera 11.6进行比较时,我们发现
- 在chrome本地绑定几乎比模拟版本的bind 慢5倍。opera原生bind中的
- 几乎比模拟bind 快4倍。
这里bind的模拟版本是
var emulatebind = function (f, context) {
return function () {
f.apply(context, arguments);
};
};
有很好的理由为什么会有这样的差异,或者这只是v8没有充分优化的问题?
注意:emulatebind
只实现了一个子集,但这并不真正相关。如果您有一个功能齐全且经过优化的模拟绑定,那么基准测试中的性能差异仍然存在。
基于http://jsperf.com/bind-vs-emulate/6,它添加了es5-shim版本进行比较,看起来罪魁祸首是绑定版本必须执行的额外分支和instanceof
,以测试它是否被作为构造函数调用。
每次绑定版本运行时,执行的代码本质上是:
if (this instanceof bound) {
// Never reached, but the `instanceof` check and branch presumably has a cost
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
// args is [] in your case.
// So the cost is:
// * Converting (empty) Arguments object to (empty) array.
// * Concating two empty arrays.
}
在V8源代码中,这个检查(在boundFunction
中)显示为
if (%_IsConstructCall()) {
return %NewObjectFromBound(boundFunction);
}
(纯文本链接到v8natives.js当Google代码搜索停止时)
让人有点困惑的是,至少对于Chrome 16来说,es5-shim版本仍然比原生版本快。其他浏览器对es5-shim和native的结果也不尽相同。猜测:也许%_IsConstructCall()
甚至比this instanceof bound
慢,也许是由于跨越本地/JS代码边界。也许其他浏览器有更快的方法来检查[[Construct]]
调用。
仅在ES5中实现功能齐全的bind
是不可能的。特别是规范的15.3.4.5.1到15.3.4.5.3节不能被模拟。
15.3.4.5.1,看起来像是一个可能的性能负担:在短界函数中有不同的[[Call]]
内部属性,因此调用它们可能需要一个不寻常的,可能更复杂的代码路径。
绑定函数的各种其他特定的不可仿真特性(例如arguments
/caller
中毒,以及可能独立于原始签名的自定义length
)可能会给每个调用增加开销,尽管我承认这有点不太可能。虽然看起来V8现在甚至没有实现中毒。
EDIT这个答案是猜测,但我的另一个答案有更接近的证据。我仍然认为这是一个有效的推测,但这是一个单独的答案,所以我就把它放在这里,只是让你参考另一个
bind的V8源代码是用JS实现的。
OP不模仿bind
,因为它不像bind
那样curry参数。这是一个功能齐全的bind
:
var emulatebind = function (f, context) {
var curriedArgs = Array.prototype.slice.call(arguments, 2);
return function () {
var allArgs = curriedArgs.slice(0);
for (var i = 0, n = arguments.length; i < n; ++i) {
allArgs.push(arguments[i]);
}
return f.apply(context, allArgs);
};
};
显然,一个快速的优化是
return f.apply(context, arguments);
代替curriedArgs.length == 0
,因为否则你会有两个不必要的数组创建,和一个不必要的复制,但也许本地版本真的是在JS中实现的,并且没有做那个优化。
警告:这个功能完整的bind
不能正确处理严格模式下this
参数强制转换的一些极端情况。这可能是开销的另一个来源。
- 在javascript中模拟动画很慢
- 通过Javascript重复更新DOM后,网页变得很慢
- Firefox扩展页面modonAtttach很慢
- 击倒.js的速度很慢
- AngularJs在IE上很慢
- 反应选项卡导航很慢
- 当我选择 30 天图表时,我的 Highchart 图表真的很慢
- canvas 或 requestAnimationFrame 在移动设备中很慢
- 为什么Javascript在设置变量时很慢
- 动态.js在火狐浏览器上很慢
- 给许多DIV留出余量是很慢的
- jQuery 对 scrollTop() 的响应速度很慢
- iPad上的Javascript加载速度很慢
- Chrome扩展程序弹出窗口.html很慢,打开不快?1.89KB 页面为 5 秒
- 动态网页从数据库中检索数据的速度很慢
- 为什么使用 chrome 从本网站向上/向下滚动很慢
- 用户在火狐浏览器上的输入速度很慢,但不是 chrome
- 转到页面重新加载的特定选项卡很慢
- 为什么新阵列很慢
- 为什么Function.prototype.bind很慢?