NodeJS – 嵌套的API调用循环

您好,我是NodeJs的新手,正试图找出最好的方式来获得这个事件链。 我必须做两个API调用获取所有我需要的信息。 第一个API调用只是一个ID列表,然后第二个API调用我传递ID来获取每个对象的其余信息。

但是,使用下面的方法,我不知道什么时候一切都完成了。 请有人帮助我。

function getData() { var options = { method: 'GET', uri: 'https://api.call1.com', qs: { access_token: _accessToken, } }; request(options).then(function(apires){ console.log("complete 1"); var obj = JSON.parse(apires); obj.data.forEach(function(entry) { findMore(entry.id) }); }) } function findMore(id) { var options = { method: 'GET', uri: 'https://api.call2.com', qs: { access_token: _accessToken, } }; request(options).then(function(apires){ console.log("complete 2"); var obj = JSON.parse(apires); }) } 

你可以让你的findMore方法返回一个promise,所以你可以传递一个Promise.all的数组,然后处理所有的promise。

 function getData() { var options = { method: 'GET', uri: 'https://api.call1.com', qs: { access_token: _accessToken, } }; request(options).then(function(apires){ console.log("complete 1"); var obj = JSON.parse(apires); var promises = []; obj.data.forEach(function(entry) { promises.push(findMore(entry.id)); }); return Promise.all(promises); }) .then(function (response) { // Here response is an array with all the responses // from your calls to findMore }) } function findMore(id) { var options = { method: 'GET', uri: 'https://api.call2.com', qs: { access_token: _accessToken, } }; return request(options); } 

有几件事要考虑:

如果你关心承诺的命运,总是要归还

在你的情况下, findMore不会从request返回promise,所以getData没有处理来跟踪这个promise的parsing(或拒绝)。

你可以使用Promise.all跟踪多个promise的parsing 。

Promise.all()方法返回一个单独的Promise,它parsing了当iterable参数中的所有promise都解决了的时候,或者iterable参数中没有promise的时候。 它拒绝了拒绝的第一个承诺的原因。

让我们把这些用在你的例子上:

 function getData() { var options = { method: 'GET', uri: 'https://api.call1.com', qs: { access_token: _accessToken, } }; return request(options) .then(function(apires){ var obj = JSON.parse(apires); var findMorePromises = obj.data.map(function(entry) { return findMore(entry.id) }); return Promise.all(findMorePromises); }) } function findMore(id) { var options = { method: 'GET', uri: 'https://api.call2.com', qs: { access_token: _accessToken, } }; return request(options) .then(function(apires){ return JSON.parse(apires); }) } 

我用map来构造promise的数组,但是你可以像使用foreach推入数组,类似于你的示例代码。

确保你正在处理拒绝任何承诺(通过catch )也是一个很好的做法,但我认为这不在这个问题的范围之内。

你想使用Promise.all。

所以首先,你需要一系列的承诺。 在每个循环内部,将findMore设置为一个variables,并使其返回承诺。 然后有一个你做的Promise.all(promiseArr).then(function(){console.log(“done)})

你的代码看起来像这样

 function getData() { var promiseArr = [] var options = { method: 'GET', uri: 'https://api.call1.com', qs: { access_token: _accessToken, } }; request(options).then(function(apires){ console.log("complete 1"); var obj = JSON.parse(apires); obj.data.forEach(function(entry) { var p = findMore(entry.id) promiseArr.push(p) }); }).then(function(){ Promise.all(promiseArr).then(function(){ console.log("this is all done") }) }) } function findMore(id) { var options = { method: 'GET', uri: 'https://api.call2.com', qs: { access_token: _accessToken, } }; return request(options).then(function(apires){ console.log("complete 2"); var obj = JSON.parse(apires); }) } 

Promise的基本思想是,只有在数组中的所有承诺都解决了,或者任何承诺失败的时候,它才会执行。 你可以在这里阅读更多

您需要使用Promise.all并行运行所有asynchronous请求。 你也必须返回findMoregetData的结果(它们是承诺)。

 function getData() { var options = {...}; return request(options) .then(function(apires) { console.log("complete 1"); var obj = JSON.parse(apires); var ops = obj.data.map(function(entry) { return findMore(entry.id); }); return Promise.all(ops); } function findMore(id) { var options = {...}; return request(options) .then(function(apires) { console.log("complete 2"); return JSON.parse(apires); }); } getData() .then(data => console.log(data)) .catch(err => console.log(err)); 

如果你可以使用ES7,可以用async / await来写:

 let getData = async () => { let options = {...}; let res = awit request(options); let ops = res.data.map(entry => findMore(entry.id)); let data = await Promise.all(ops); return data; }; let findMore = async (id) => { let options = {...}; let apires = awit request(options); return JSON.parse(apires); }; 

编辑:正如其他人所说,在这种情况下使用Promise.all()可能是一个更好的解决scheme。

如果您打算使用jQuery(一个JavaScript库),那么您可以使用.ajaxStop()事件处理函数并指定您自己的函数。 示例代码:

 $(document).ajaxStop(function(){ alert("All AJAX requests are completed."); }); 

您将需要包含jQuery模块。 Node.js的说明是:

  1. 通过npm安装模块:

     npm install jquery 
  2. 然后,在你的JavaScript代码中使用“require”来使用jQuery(一个带有文档的窗口是必需的,但是Node中没有这样的“窗口”,所以你可以用jsdom来模拟一个窗口),详情参见npm-jQuery :

     require("jsdom").env("", function(err, window) { if (err) { console.error(err); return; } var $ = require("jquery")(window); }); 

如果你想坚持纯粹的JavaScript方法,你将需要创build自己的“模块”来跟踪AJAX请求。 在这个模块中,您可以跟踪有多less未决的请求,并在终止时将其删除。 请参阅: 检查所有Ajax请求何时完成 – 纯JavaScript以获取更多详细信息。