【问题标题】:Async parallel bug?异步并行错误?
【发布时间】:2013-02-11 23:02:58
【问题描述】:

在这里,我试图创建一个带有 Async.js 参数的函数数组。

该数组由 RunRequest 的实例组成,这些实例应该设置在 MakeRequest 的循环中,就在我尝试将函数数组传递给 Async 之前。

所以当我将 request[i] 中的请求传递给 RunRequest 时,它没有问题,但在 RunRequest 函数内部它是未定义的?

// Process Requests
function RunRequest(db, collection, request, requestHandler, callback) {
    console.log('this happening?')
    // Connect to the database
    db.open(function(err, db) {
        if(err) callback(err, null);
        // Connect to the collection
        db.collection(collection, function(err, collection) {
            if (err) callback(err, null);
            // Process the correct type of command
            requestHandler(db, collection, request, callback);  
        });
    });
}

function MakeRequest(request, requestHandler, collection, callback) {
    var data = [];
    var doneRequest = function(err, results) {
        console.log('done was called')
        if (err) callback(err, null);
        else if(results) data = data.concat(results);
    }
    // Make Request Array
    var requestArray = [];
    for(var i = 0; i < request.length; i++) {
        console.log('run request was called')
        var dbConnection = new Db('KidzpaceDB', new Server(Host, Port, {auto_reconnect: true}))
        requestArray.push(function() {RunRequest(dbConnection, collection, request[i], requestHandler, doneRequest)});
    }
    // Make all requests in Parallel then invoke callback
    Async.parallel(requestArray, function(err, results) {
        console.log('Step WORKS')
        if(data) {
            var uniqueResults = [];
            for(var i = 0; i < data.length; i++) {
                if( !uniqueResults[data[i]['_id']] ) {
                    uniqueResults[uniqueResults.length] = data[i];
                    uniqueResults[data[i]['_id']] = true;
                }
                callback (null, uniqueResults);
            }
        }
    });
}


// Request Handlers
var FindHandler = function(db, collection, request, callback) {
    console.log('FindHandler was called')
    console.log('Request Query' + request);
    collection.find(request.query, function(err, cursor) {
        if (err) callback(err, null);
        cursor.toArray(function(err, docs) {
            if (err) callback(err, null);
            if(docs.length <= 0) console.log("No documents match your query");
            var requestResults = [];
            for(var i=0; i<docs.length; i++) {
                requestResults[requestResults.length] = docs[i]; 
            }
            db.close();
            callback(null, requestResults);
        });
    });
}

【问题讨论】:

    标签: javascript node.js async.js node-async


    【解决方案1】:

    这只是在黑暗中拍摄:

    我认为问题在于你如何在MakeRequest 中调用RunRequest。在第一个 for 循环中,您正在迭代 request 并在匿名函数中使用 request[i],但 i 在下一次迭代中发生变化,并且当 RunRequest 实际执行时,当前范围会丢失。

    很难重现,但试试这个:

    var requestArray = [];
    for(var i = 0; i < request.length; i++) {
        console.log('run request was called')
        var dbConnection = new Db('KidzpaceDB', new Server(Host, Port, {auto_reconnect: true}))
    
        function wrap(dbConnection, collection, request, requestHandler, doneRequest) {
            return function() {
                RunRequest(dbConnection, collection, request, requestHandler, doneRequest);
            }
        }
        requestArray.push(wrap(dbConnection, collection, request[i], requestHandler, doneRequest));
    }
    

    【讨论】:

      【解决方案2】:

      这是一个范围界定问题。当循环结束变量i被设置为request.length,所以request[i]就是undefined

      用这样的匿名函数包装你的代码:

      var requestArray = [];
      for(var i = 0; i < request.length; i++) {
          (function(i) {
              console.log('run request was called');
              var dbConnection = ...;
              requestArray.push( ... );
          })(i);
      }
      

      甚至更好(在创建匿名函数时避免不必要的开销):

      var requestArray = [];
      request.forEach( function( el ) {
          console.log('run request was called');
          // the other code goes here, use el instead of request[i]
      });
      

      EDIT 未调用回调,因为您没有正确定义数组中的函数。您将不得不稍微重构您的代码,所以让我向您展示它应该是怎样的:

      requestArray.push(function(callback) { // <---- note the additional parameter here
          // do some stuff, for example call db
          db.open(function(err, db) {
              if (err) {
                  callback( err );
              } else {
                  callback( );
              }
          });
      });
      

      如果你想使用RunRequest,那么你需要将callback作为附加参数传递给RunRequest(所以使用callback而不是doneRequest)。

      【讨论】:

      • 效果好多了,但不幸的是 Async.parallel 回调仍然没有被调用...
      猜你喜欢
      • 2019-05-13
      • 2013-03-20
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2015-11-02
      • 2020-07-08
      • 2016-11-22
      • 1970-01-01
      相关资源
      最近更新 更多