嵌套在 async.js 瀑布中的异步函数
Posted
技术标签:
【中文标题】嵌套在 async.js 瀑布中的异步函数【英文标题】:Async function nested within async.js waterfall 【发布时间】:2014-05-09 03:20:40 【问题描述】:免责声明:非工程师,对 JS 很陌生
大家好 - 我正在尝试利用 async.js 模块将一组函数链接在一起。我想要的输出是迭代mapData
(对象数组),然后将其传递给最终函数(现在 - 只是 console.log(result)。
async.waterfall([
function( callback )
getCoords ( function( data )
mapData = data;
);
callback(null, mapData);
,
function( mapData, callback )
//getEmail ( mapData );
callback( null, mapData );
], function( err, result )
console.log( result );
);
但是,getCoords
包含另一个异步函数(找到 here)。我看到的是第一个回调(null,mapData)在它返回之前发生,导致 null 结果。
我如何构造它以便getCoords
在继续下一个块之前返回mapData
?我可能遗漏了一些非常明显的东西,谢谢!
【问题讨论】:
这就是你所做的一切,如果是这样,你为什么还需要异步,只需将getEmail
函数放在getCoords
回调中?
@adeneo 这可能只是大型实现的一小部分,philsometypaway 需要一些东西来实现连续传递样式。
@JasonAller 是正确的 - 我需要将一堆这些链接在一起。谢谢你们的帮助!
【参考方案1】:
回调乐趣...您需要了解使用回调时程序流程是如何工作的。这可以通过一个非常简单的例子看出。
示例:
function doWork( callback )
console.log( 2 );
setTimeout(callback, 1000);
function master ()
console.log(1);
doWork(function ()
console.log(3);
);
console.log(4);
master();
预期的结果是控制台日志的正确顺序是 1、2、3、4。但是在运行示例时,您会看到一些奇怪的东西,因为日志的顺序是 1、2、4、3。这是因为日志记录3 个发生在 doWork
完成之后,而 4 个记录发生在启动 doWork
之后,而不是等待它完成。
异步:
您可以使用异步库做很多事情,但要记住最重要的一点是回调函数始终将错误作为第一个参数接收,然后是您要传递的参数到列表中的下一个函数。
您链接到的gist 未设置为以这种方式返回。您可以修复它或在代码中处理它。首先让我们按原样使用函数:
使用现有的 getCoords:
async.waterfall([
function( callback )
// getCoords only returns one argument
getCoords ( function( mapData )
// First argument is null because there
// is no error. When calling the waterfall
// callback it *must* happen inside the getCoords
// callback. If not thing will not work as you
// have seen.
callback( null, mapData);
);
,
function( mapData, callback )
// Do work with the results of the 1st step
// in the waterfall.
// Finish the water fall
callback( null, mapData );
], function( err, result )
if ( err )
console.log( err );
return;
console.log( result );
);
现在getCoords
有两个问题。首先是它没有向它的回调返回正确的参数,其次它并不总是使用它的回调。这第二个问题是巨大的,因为它会导致你的程序挂起和中断。
我已在函数中评论了已进行的 2 个修复。
固定 getCoords:
function getCoords ( callback )
var query = new Parse.Query( 'userGeoCoordinates' );
query.exists( 'location' )
query.find(
success: function ( result )
for ( var i = 0; i < result.length; i++ )
var object = result[ i ];
var user = ;
user.userId = object.get( 'userId' );
user.coords = [];
if ( !user_dedupe( user.userId ) )
all_users.push( user );
for ( var i = 0; i < all_users.length; i++ )
for ( var j = 0; j < result.length; j++ )
var object = result [ j ];
if( object.get( 'userId' ) == all_users[ i ].userId )
all_users[i].coords.push(
[ object.get( 'location' )._longitude , object.get( 'location' )._latitude ]
);
// This is the original callback, let fix it
// so that it uses the normal return arguments
// callback( all_users );
// Return null for no error, then the resutls
callback( null, all_users );
,
error: function( error )
// Here is the second, bigger, issue. If the
// getCoords had an error, nothing the callback
// isn't called. Lets fix this
// console.log( 'error' );
// Return the error, an no results.
callback( error );
);
修复getCoords
函数后,您可以简化瀑布:
第一个简化瀑布:
async.waterfall([
function( callback )
// getCoords returns the expected results
// so just pass in our callback
getCoords ( callback );
,
function( mapData, callback )
// Do work with the results of the 1st step
// in the waterfall.
// Finish the water fall
callback( null, mapData );
], function( err, result )
if ( err )
console.log( err );
return;
console.log( result );
);
但是异步有一个很好的特性。如果您的瀑布步骤只是调用一个返回预期结果的函数,您可以使用 async.apply 进一步简化它。
第二个简化瀑布:
async.waterfall([
async.apply( getCoords ),
function( mapData, callback )
// Do work with the results of the 1st step
// in the waterfall.
// Finish the water fall
callback( null, mapData );
], function( err, result )
if ( err )
console.log( err );
return;
console.log( result );
);
【讨论】:
嗨,我是 javascript 的新手,我想问一个问题,在你的例子中你称之为 callback(null, mapData);或者说每个人都在我看到 async.waterfall 的最后使用回调()。我想知道回调函数的用途以及它在哪里定义 @rahul - 回调函数是作为瀑布的一部分为您定义的。它作为最后一个参数传递给数组中的每个函数。当你调用这个函数时,它基本上是在调用数组中的下一个函数。【参考方案2】:尝试将瀑布的第一个函数的回调放在getCoords
回调中。这样,只有在 getCoords
回调设置了 mapData
后,才会调用瀑布中的第二个函数,此外,当您调用回调时,mapData
现在将在范围内。
async.waterfall([
function( callback ) // F1
getCoords ( function( data )
mapData = data;
callback(null, mapData); // this is the entry point for F2
);
,
function( mapData, callback ) // now F2 is invoked only after mapData is set
//getEmail ( mapData );
callback( null, mapData );
],
function( err, result )
console.log( result );
);
【讨论】:
以上是关于嵌套在 async.js 瀑布中的异步函数的主要内容,如果未能解决你的问题,请参考以下文章