使用异步node.js函数控制流和错误处理

时间:2014-07-22 07:19:52

标签: node.js asynchronous callback control-flow

我有一个函数,其中许多小进程独立发生,但所有这些进程的结果必须进入最终回调。这不是一个非常不合理的情况;这种代码,你不一定提前知道将要运行什么,什么时候,以及多长时间是相当普遍的,但在这之前几个小时之后,我无法找到一种巧妙的方法。我不是要求几个小时的代码时间,只是简单解释如何做到这一点。

下面的wrapper函数完成了一系列任务,即异步函数,其执行方式是在执行之前不确定将运行什么,何时以及执行多少次。我试图找到一个简单的方法来调用回调(final callback注释)一旦完成它们,如果它们没有先失败,但在失败时立即退出包装函数。这类情况的示例将如下所示。

// Definition for wrapper function
function wrapper(callback) {
    asyncfunction1();
    for(/*conditions*/) {
        asyncfunction2();
    }
    asyncfunction3(function(results) {
        asyncfunction4(results);
        for(res in results) {
            asyncfunction5(res);
        }
    });
}

// Call to wrapper function
wrapper(function(err) {                // final callback
    if (err) console.log("Failure");
    else console.log("Success");
});

wrapper包含一系列函数(asyncfunction#()),这些函数必须全部成功完成才能将回调调用为callback(false)。如果任何一个失败,则调用回调,然后调用callback(true)并退出整个包装器,而不关闭进程。

我的绊脚石:

  • 有没有办法在使用内置事件从包装函数退出时调用回调?
  • 是否存在一种本地方式从几个函数中退出包装函数而不会终止整个过程?

1 个答案:

答案 0 :(得分:1)

我还建议使用async.js,你会有一些嵌套调用。异步是针对这种类型的事情 - NodeJS中的控制流很棘手。还有其他软件包(promises,其他异步软件包等)。

下面是使用async的示例。请注意,如果您的流可以并行运行,则外部.series方法可以是.parallel。我喜欢在外部resultsObj中传递内容,这些内容会延续到每个异步调用。它可以包含数组,值,对象等。 。 。只是一个持有人。

我也在使用.series表示法,其中传入了命名函数的对象,而不是函数数组。存储了传递给回调的值,我在asyncFunction4中使用了它。

var resultsObj = {};
async.series( {
  asyncFunction1: function( seriesCb ) {
    //do stuff
    seriesCb();
  },
  asyncFunction2: function( seriesCb ) {
    async.each( yourArray2, function( item, eachCb ) {
      //do stuff
      eachCb();
    }, function( errEach ) {
      resultsObj.someFlag = true;
      seriesCb( errEach );
    } );
  },
  asyncFunction3: function( seriesCb ) {
    callAsyncFunction3( function( results3 ) {
      async.series( {
        asyncFunction4: function( innerSeriesCb ) {
          var results4 = "yes";
          innerSeriesCb( results4 );
        },
        asyncFunction5: function( innerSeriesCb ) {
          async.each( yourArray5, function( item, eachCb ) {
            //do stuff
            eachCb();
          }, function( errEach ) {
            innerSeriesCb( errEach );
          } );
        }
      }, function( innerSeriesErr, innerSeriesResults ) {
        console.log("Result value of async4 was " + innerSeriesResults.asyncFunction4 );
        seriesCb( innerSeriesErr, innerSeriesResults );
      } );
    } );
  }
}, function( seriesErr, seriesResults ) {
  if ( seriesErr ) console.log( "Failure" );
  else console.log( "Success.  results=" + JSON.stringify( resultsObj ) );
} );

编辑:还有一件事。你会注意到这个控制骨架已经有多大了。这没有代码。拆分您的方法并让它们接受(并使用)典型的NodeJS callback(err)callback(err, results)样式。然后在异步流中,以较短的方式调用它们。它只会使这个大型控制文件更容易管理。

function doSomething( input1, input2, callback ){
  if( input1 === input2 ) return callback( new Error("Cannot be equal") );
  callback( null, "Success ");
}

async.series( {
  asyncFunction1: function( seriesCb ) {
    doSomething( 1, 2, seriesCb );
  }
}, function( seriesErr, seriesResults ) {
  if ( seriesErr ) console.log( "Failure" );
  else console.log( "Success" );
} );