如何处理Node.js中的回调?

如何处理Node.js中的回调?,node.js,callback,Node.js,Callback,假设我有3个文件 index.js像这样对后端进行调用 $.post('/test/', data, function(response) { //handle success here }) app.post('/test/', function(req, res){ item.getItems(function(response){ res.json(response); }); }); js会像这样处理路由 $.post('/test/', data, fun

假设我有3个文件

index.js像这样对后端进行调用

$.post('/test/', data, function(response) {
 //handle success here
})
app.post('/test/', function(req, res){
   item.getItems(function(response){
     res.json(response);
   });
 });
js会像这样处理路由

$.post('/test/', data, function(response) {
 //handle success here
})
app.post('/test/', function(req, res){
   item.getItems(function(response){
     res.json(response);
   });
 });
js是访问数据库并对每个项目发出POST请求的模型

function getItems(callback) {
  database.query('SELECT * from items', function(result){
    result.forEach(function(item){
        request.post('/api/', item, function(req, res) {
          //finished posting item
        });
    });   
  });
  //callback here doesnt wait for calls to finish
}

我应该在何处/何时调用传递给getItems()的回调来处理index.js中的成功/失败?

在服务器端代码中发出API请求似乎很奇怪,除非这是某种与API交互的中间层代码。。。但是您正在与数据库交互,所以我仍然不明白为什么不能只进行数据库插入,或者进行批量插入API调用

不管怎样,如果你必须按照你要求的方式去做,我在过去用一个递归方法来修剪结果数组。。。我真的不知道这是不是一个好方法,所以我想听听任何反馈。大概是这样的:

function recursiveResult(result, successfulResults, callback) {
  var item = result.shift();
  // if item is undefined, then we've hit the end of the array, so we'll call the original callback
  if (item !== undefined) {
    console.log(item, result);
    // do the POST in here, and in its callback, call recursiveResult(result, successfulResults, callback);
    successfulResults.push(item);
    return recursiveResult(result, successfulResults, callback);
  }
  // make sure callback is defined, otherwise, server will crash
  else if (callback) {
    return callback(successfulResults);
  }
  else {
    // log error... callback undefined
  }
}

function getItems(callback) {
  var successfulResults = [];
  var result = [1, 2, 3, 4];
  recursiveResult(result, successfulResults, callback);
}

console.log('starting');
getItems(function(finalResult) {
  console.log('done', finalResult);
});

因为您的
request.post()
操作是异步的,所以您必须使用某种方法跟踪它们何时完成,然后才能调用回调。有多种方法可以做到这一点。我将概述以下几点:

手动跟踪请求操作的计数

function getItems(callback) {
  database.query('SELECT * from items', function(result){
    var remaining = result.length;
    result.forEach(function(item){
        request.post('/api/', item, function(err, res) {
          --remaining;
          //finished posting item
          if (remaining === 0) {
              callback();
          }
        });
    });   
  });
}
// load Bluebird promise library
var Promise = require('bluebird');

// promisify async operations
Promise.promisifyAll(request);

function queryAsync(query) {
    return new Promise(function(resolve, reject) {
        // this needs proper error handling from the database query
        database.query('SELECT * from items', function(result){
            resolve(result);
        });
    });
}

function getItems(callback) {
    return queryAsync('SELECT * from items').then(function(result) {
        return Promise.map(result, function(item) {
            return request.postAsync('/api/', item);
        });
    });
}

getItems.then(function(results) {
    // success here
}, function(err) {
    // error here
})
手动执行此操作的主要问题是,当您真正了解如何处理错误时,在嵌套异步操作中传播错误是很困难的。在这里显示的其他方法中,这要容易得多

使用承诺

function getItems(callback) {
  database.query('SELECT * from items', function(result){
    var remaining = result.length;
    result.forEach(function(item){
        request.post('/api/', item, function(err, res) {
          --remaining;
          //finished posting item
          if (remaining === 0) {
              callback();
          }
        });
    });   
  });
}
// load Bluebird promise library
var Promise = require('bluebird');

// promisify async operations
Promise.promisifyAll(request);

function queryAsync(query) {
    return new Promise(function(resolve, reject) {
        // this needs proper error handling from the database query
        database.query('SELECT * from items', function(result){
            resolve(result);
        });
    });
}

function getItems(callback) {
    return queryAsync('SELECT * from items').then(function(result) {
        return Promise.map(result, function(item) {
            return request.postAsync('/api/', item);
        });
    });
}

getItems.then(function(results) {
    // success here
}, function(err) {
    // error here
})

谢谢,服务器端的API请求仅用于更新另一台服务器上的项目。这看起来是个不错的选择,尽管有点复杂。如果没有其他更简单的解决方案,我可以选择这个。我的另一个想法是使用lodash after函数并在那里调用回调..啊,好的,这就是我的想法。您不能进行批量API调用吗?如果你已经抽象出了你个人帖子的逻辑,那么就很容易创建一个批量插入方法。我同意这有点复杂,一开始非常混乱,但这似乎为我完成了工作。你能解释一下批量API调用是什么意思吗?批量API调用,我的意思是你的端点将使用一个项目数组,而不是单个项目。。。因此,你不必一直点击单个POST端点并担心回调的位置。啊,我明白你的意思了。所以只需发布整个项目,而不是单个项目,对吗?不幸的是,我无法访问该端点如何处理数据,因此这是不可能的。我还没有尝试,明天我将首先尝试。谢谢。@jfriend00,我很想知道
Promise.map
是如何与
getItems
的//error-here部分对齐的。。。假设您有20个项目用于
postAsync
,其中15个成功,5个失败。。。15位在
结果
中表示成功,5位在
错误
中表示错误?我对承诺的作用有很高的理解,但我还没有看到一个承诺数组的例子。@incutonez-
Promise.map()
在这方面与ES6
Promise.all()类似。bluebird文档是这样写的:如果数组中的任何承诺被拒绝,或者映射器函数返回的任何承诺被拒绝,那么返回的承诺也会被拒绝。@incutonez-如果您想知道所有承诺何时完成,希望所有成功的结果,以及哪些失败,那么生活就有点复杂了。为此,您需要创建一系列承诺并使用Bluebird,然后检查每个结果,看看哪些成功,哪些失败。这里有一个相关的问题:@incutonez-这里是一个
.settle
类型行为的简单JS实现:。