2

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

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

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

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

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

4

2 回答 2

2

您可以使用提供另一个上下文Function.prototype.bind(thisArg [, arg1 [, arg2, …]])bind返回一个新方法,在调用该方法时,其this关键字设置为thisArg. 在你的情况下:

longRunningFunction(mycallback.bind(uniqueContext));

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

于 2013-02-01T06:31:38.763 回答
2

假设这段代码:

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

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

现在,如果你有这个:

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

标准规定context参数 ofmyCallbackuniqueContext 在触发回调的那一刻。当您在循环中尝试这样的事情时,它可能会导致一些问题(因为您将uniqueContext在每次迭代时擦除)。

如果你这样做:

var uniqueContext1 = getUniqueContext1( );
longRunningFunction( function ( ) { myCallback( uniqueContext1 ); } );

var uniqueContext2 = getUniqueContext2( );
longRunningFunction( function ( ) { myCallback( uniqueContext2 ); } );

回调 using保证在第一个结束uniqueContext1时调用,而在第二个结束时调用 using (具有与以前相同的限制;如果您覆盖或在您的范围内的某处,回调参数也会改变)。longRunningFunctionuniqueContext2longRunningFunctionuniqueContext1uniqueContext2

使用 bind 可以避免创建闭包(以及前面提到的默认值)。下面的代码与前面的代码类似,除了你永远无法通过覆盖前面的代码来意外更改参数的值:

longRunningFunction( mycallback.bind( null, getUniqueContext1( ) ) );
longRunningFunction( mycallback.bind( null, getUniqueContext2( ) ) );

mycallback.bind( null, someParameter )将返回一个函数,该函数在调用时将mycallback使用nullas this(将回退到window像任何常规函数一样)和someParameter作为第一个参数调用。

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

于 2013-02-05T02:22:31.420 回答