【问题标题】:Will Function.prototype.bind() always be slow?Function.prototype.bind() 会一直很慢吗?
【发布时间】:2013-09-24 13:47:43
【问题描述】:

我正在编写一个开源 javascript 库,并且我大量使用.bind() 方法,因为我认为面向对象的代码看起来更清晰。 (值得商榷

示例

A1:

var that = this;

setTimeout(function () {
    that.method();
}, 0);

B1:

setTimeout(this.method.bind(this), 0);

或者,更实用的代码部分

A2:

remoteDataSource.getData(function (a, b, c, d) {
     obj.dataGetter(a, b, c, d);
})

vs B2:

remoteDataSource.getData(obj/* or prototype */.dataGetter.bind(obj));

我在旧版浏览器中使用非原生 bind,一切都很完美,直到我打开 jsperf benchmark for bind

使用bind 的代码看起来慢了 100 倍。现在,在重写我所有的库之前,我有一个问题要问那些熟悉 javascript 引擎的人:

作为新功能,bind 是否有可能得到优化 很快,还是因为 JavaScript 架构限制没有机会?

【问题讨论】:

标签: javascript performance v8 spidermonkey late-binding


【解决方案1】:

目前,在 2013 年末,最好的解决方案将是实现 Function.prototype.bind手工制作 版本,并使用您自己的 javascript 代码覆盖供应商的“本机”(不是真正的本机)方法,或者使用你自己的myBind

Function.prototype.apply 相当快,而数组切片、连接和移位很慢,因此如果bind 最好使用apply,或者尽量减少myBind 函数中的参数操作。这将使您没有参数预填充的功能。

所以我认为没有必要将所有内容重写为闭包(丑陋的var that = this;)。让 javascript 的功能特性获胜。

更多细节和工作代码示例在这里:

http://jsperf.com/function-bind-performance/4

http://jsperf.com/function-bind-performance/5

http://jsperf.com/bind-vs-emulate/4 .. 10.

总结:找到的解决方法还不错。勇敢地使用它们。如果您使用功能不全的bind,请不要离最初的概念太远,因为我没有发现它尚未在 C 中实现的原因。这是时间问题。

【讨论】:

  • 瓶颈中仍然使用闭包
【解决方案2】:

首先,修复jsperf http://jsperf.com/bind-vs-emulate/13

=您不应在基准测试中重新创建静态函数。这是不现实的,因为在实际代码中静态函数只创建一次。

您可以看到var self = this 模式仍然快了大约 60%。但它需要将函数定义内联到可以从任何地方绑定的位置,因此具有更好的可维护性。


不,内置的绑定语义非常复杂。

当我绑定时,我只想要这个:

function bind(fn, ctx) {
    return function bound() {
        return fn.apply(ctx, arguments);
    };
}

如果我想预先应用参数或使用一些深层的构造函数黑魔法,我会想要一个完全不同的函数。我不知道为什么这些都包含在 bind 中。

顺便说一句,ES5 中引入的几乎所有东西都存在同样的问题,通过强制实现处理一些与实践中的任何人都不合理相关的理论边缘情况来惩罚常见情况。下一个语言版本继续沿同一路径前进。

模拟绑定甚至根本不尝试模拟绑定。即使你试图模仿它,你也无法 完全这样做是不公平的。

因此,在其他所有条件相同的情况下*,内置绑定不会比仅绑定的常识自定义绑定更快。

*在 JIT 中,用户代码与内置代码相比没有明显的劣势。事实上,SM 和 V8 都实现了许多内置功能 在 Javascript 中。

【讨论】:

  • 今天在 Firefox 中运行测试显示 .bind() 在 Chrome 中最快但最慢。您提出了很多好的观点,但内置绑定不能更快的结论似乎不正确。虽然绑定函数确实有一定的开销,但它也消除了一些开销。特别是,它不需要调用不同的函数,而是共享原始函数的主体,因此非常接近于调用原始函数。它也不需要遍历变量范围来获取它绑定的值。所以我认为它总是归结为实现细节而不是规范。
  • 很抱歉对旧答案的评论,但有人参考了它。
  • 这些天本地绑定似乎很快:jsperf.com/bind-vs-closure-2019
  • 相应地更新了答案。 Chrome 开发人员的惊人优化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 2012-02-24
  • 1970-01-01
  • 2019-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多