Async函数嵌套在async.js瀑布中

免责声明:非工程师,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包含另一个asynchronous函数(在这里find)。 我所看到的是第一个callback(null,mapData)发生在它返回之前,导致一个空结果。

我如何构造这个以便mapData在返回到下一个块之前返回mapData ? 我可能错过了一些超级明显的东西,谢谢!

callback的乐趣…您需要了解如何使用callback程序stream程的工作原理。 这可以用一个非常简单的例子来看。

例:

 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的顺序排列的控制台日志。但是,在运行该示例时,您会看到一些奇怪的事情,因为日志的顺序是1,2,4,3。这是因为logging3发生doWork完成后,启动完成后会发生4个日志logging,而不是等待它完成。

asynchronous:

您可以使用asynchronous库做很多事情,但重要的是要记住,callback函数总是接收错误,作为第一个参数,然后是要传递给列表中下一个函数的参数。

你链接到的要点没有设置返回这种方式。 你可以修复它或者在你的代码中处理它。 首先让我们直接使用这个函数:

使用现有的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有两个问题。 首先,它不会将正确的参数返回给它的callback,其次它并不总是使用它的callback函数。 这第二个问题是巨大的,因为它会导致您的程序挂起和打破。

我已经在函数中修改了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 ); } }); } 

随着getCoordsfunction的修复,您可以简化您的瀑布:

第一个简化瀑布:

 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 ); }); 

但asynchronous有一个很好的function。 如果您的瀑布步骤只是调用一个返回期望结果的函数,则可以通过使用async.apply进一步简化它。

2st简化瀑布:

 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 ); }); 

尝试在getCoordscallback中放置瀑布的第一个函数的callback函数。 这样瀑布中的第二个函数只有在getCoordscallback已经设置了mapData之后才会被调用,另外mapData现在将在调用callback的时候处于范围之内。

 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 ); });