我如何避免这种“最终callback”模式?

假设我有以下代码:

var foo = function( arg, continuation, behavior ) { if ( arg > 1 ) { // Do some work with arg, for example send a paged API request. console.log("foo: " + arg--); continuation( arg, continuation, behavior ); } else { behavior( arg ); } }, bar = function( arg, continuation, behavior ) { if ( arg > 2 ) { // Do some other work with arg. console.log("bar: " + arg--); bar( arg, continuation, behavior ); } else { continuation( arg, continuation, behavior ); } }; bar( 3, foo, console.log ); 

这个想法是,我想在调用中指定哪个函数最终成为foo的callback函数,这将在稍后的调用图中被调用。

例如,我可能不想console.log arg的最终值,而是将其用作一些消息重复的次数:

 var baz = function( arg ) { for (var i = 0; i < arg; i++) { console.log("baz"); } }; bar( 4, foo, baz ); 

在这种情况下,我说我正在注入 baz行为而不是console.log行为。

在我写的一些代码中,我使用这个模式来注入我想要的行为。 例如, cli.js注入打印某些logging到控制台的行为,而其他一些文件db.js (尚未写入)可能会注入将这些logging添加到数据库的行为,依此类推。

我不确定这是否是实现我想要的最佳方式。 有没有更好的方法来做到这一点?

您提示您将执行一些asynchronous任务,所以我们来模拟一个asynchronous任务:

 function mockApiRequest(mockResponse, callback) { setTimeout(function() { callback(mockResponse) }, 500); } 

现在让我们修改你的代码来使用我们的api请求:

 function sendPages(pageNumber, continuation, behavior) { if ( pageNumber > 1 ) { behavior('Uploading ' + pageNumber); mockApiRequest({success:true}, function(apiResponse) { if (apiResponse.success) { behavior('Successfully uploaded ' + pageNumber); continuation(pageNumber-1, continuation, behavior); } else { behavior('Failed to upload ' + pageNumber); } }); } else { behavior('Unsure what to do with ' + pageNumber); } } 

正如Aadit所说的,你的函数修改传入的值并不是一件好事。 这是函数的“副作用”,如果不能期望在执行过程中值相同,将会使debugging变得非常困难。 所以你应该为下一个继续呼叫创build一个新的值。 你应该考虑arg不可变的 ,而不是在原地修改arg并传递arg