将上下文添加到无上下文的Javascript回调中

时间:2013-01-28 17:58:56

标签: javascript javascript-events callback

我正在使用具有特定长期运行功能的第三方JavaScript库(它涉及通过网络进行的Web服务调用等)。为简单起见,假设它需要一个参数,一个回调函数在长时间运行的操作完成时调用,所以假设我们有签名longRunningFunction(callback)

不幸的是,该函数不接受“context”参数,所以如果我多次调用longRunningFunction,当我的回调被调用时,我无法知道哪个调用导致了哪个回调。

我通过使用匿名函数找到了以下解决方法:定义一个mycallback(context)函数,然后在每次调用长时间运行的操作时执行类似的操作:

uniqueContext = getUniqueContextFromSomewhere();
longRunningFunction(function() {mycallback(uniqueContext)});

这个似乎可以工作,但我的问题是,在所有可能的情况下,这是否保证根据JavaScript规范工作,因为长时间运行操作可能在不同的线程上执行,对longRunningFunction的各种调用的回调可能以任何顺序进行,等等。那么,我找到的解决方案是否有效?

2 个答案:

答案 0 :(得分:2)

您可以使用Function.prototype.bind(thisArg [, arg1 [, arg2, …]])提供其他背景信息。 bind会返回一种新方法,在调用时,其this关键字设置为thisArg。在你的情况下:

longRunningFunction(mycallback.bind(uniqueContext));

这在较旧的浏览器中不起作用(例如IE小于9)但您可以使用polyfill或库Underscore.js。要了解有关bind的更多信息,请参阅以下资源:

答案 1 :(得分:2)

假设这段代码:

function longRunningFunction( fn ) {
    window.setTimeout( fn, 1000 ); // just to make it async
}

function myCallback( context ) {
    /* ... */
}

现在,如果你有这个:

var uniqueContext = getUniqueContext( );
longRunningFunction( function ( ) { myCallback( uniqueContext ); } );

标准规定,context myCallback参数在{@ 1}} 将会被触发回调。当你在循环中尝试这样的事情时会导致一些问题(因为你会在每次迭代时擦除uniqueContext)。

如果你这样做:

uniqueContext

使用var uniqueContext1 = getUniqueContext1( ); longRunningFunction( function ( ) { myCallback( uniqueContext1 ); } ); var uniqueContext2 = getUniqueContext2( ); longRunningFunction( function ( ) { myCallback( uniqueContext2 ); } ); 的回调可以保证在第一个uniqueContext1结束时被调用,而当第二个longRunningFunction将结束时使用uniqueContext2进行回调(具有相同的回复)限制比以前;如果在范围内的某处覆盖longRunningFunctionuniqueContext1,则回调参数也会改变。)

使用bind可以避免创建闭包(以及前面提到的默认值)。以下代码与前一个代码类似,不同之处在于您将永远无法通过覆盖前一个代码来意外更改参数的值:

uniqueContext2

longRunningFunction( mycallback.bind( null, getUniqueContext1( ) ) ); longRunningFunction( mycallback.bind( null, getUniqueContext2( ) ) ); 会返回一个函数,该函数在被调用时会调用mycallback.bind( null, someParameter ) mycallback作为null(它会像任何常规函数一样回退到this )和window作为第一个参数。

另一个答案是仅使用someParameter的第一个参数,因为它们使用bind变量,但它不是必需的,您可以安全地使用函数参数。