节点 – 等待循环完成?

当下面的函数完成并提供数组“相册”中项目的最终列表时,我希望它调用另一个函数/对列表执行其他操作。

目前它在函数完成之前发布[],我知道这是因为asynchronous执行,但我认为节点线性读取,因为它是单线程?

function getAlbumsTotal(list, params){ for(var i = 0; i<list.length; i++){ api.getArtistAlbums(list[i], params).then(function(data) { for(var alb = 0; alb<data.body.items.length; alb++){ albums.push(data.body.items[alb].id); } }, function(err) { console.error(err); }); } console.log(albums); //do something with the finalized list of albums here } 

您提供的callback函数实际上是asynchronous执行的,这意味着只有在当前调用堆栈中的其余代码执行完毕后(包括最终的console.log )才会执行该callback函数。

以下是你如何做到这一点:

 function getAlbumsTotal(list, params){ var promises = list.map(function (item) { // return array of promises // return the promise: return api.getArtistAlbums(item, params) .then(function(data) { for(var alb = 0; alb<data.body.items.length; alb++){ albums.push(data.body.items[alb].id); } }, function(err) { console.error(err); }); }); Promise.all(promises).then(function () { console.log(albums); //do something with the finalized list of albums here }); } 

NB:显然albums被定义为一个全局variables。 这不是一个好devise。 每个承诺都会提供自己的专辑子集, Promise.all调用将被用来将这些结果连接成一个局部variables。 这是怎么样的:

 function getAlbumsTotal(list, params){ var promises = list.map(function (item) { // return array of promises // return the promise: return api.getArtistAlbums(item, params) .then(function(data) { // return the array of album IDs: return Array.from(data.body.items, function (alb) { return alb.id; }); }, function(err) { console.error(err); }); }); Promise.all(promises).then(function (albums) { // albums is 2D array albums = [].concat.apply([], albums); // flatten the array console.log(albums); //do something with the finalized list of albums here }); } 

如果你想使用从node.js中的循环返回的数据,你必须添加一些额外的代码来检查你是否在循环的最后一次迭代。 基本上,只有在条件为真的情况下才能编写自己的“循环完成”检查并运行。

我继续写下一个完整的,可运行的例子,这样你就可以分解它,看看它是如何工作的。 最重要的部分是添加一个计数器,在每个循环之后递增计数器,然后检查计数器是否与迭代列表的长度相同。

 function getArtistAlbums(artist, params){ var artistAlbums = { 'Aphex Twin':['Syro', 'Drukqs'], 'Metallica':['Kill \'Em All', 'Reload'] }; return new Promise(function (fulfill, reject){ fulfill(artistAlbums[artist]); }); } function getAlbumsTotal(list, params){ var listCount = 0; for(var i = 0; i<list.length; i++){ getArtistAlbums(list[i], params) .then(function(data) { listCount++; for(var alb = 0; alb<data.length; alb++){ //for(var alb = 0; alb<data.items.length; alb++){ //albums.push(data.body.items[alb].id); albums.push(data[alb]); } // print out album list at the end of our loop if(listCount == list.length){ console.log(albums); } }, function(err) { console.error(err); }); } // prints out too early because of async nature of node.js //console.log(albums); } var listOfArtists = ['Aphex Twin', 'Metallica']; var albums = []; getAlbumsTotal(listOfArtists, 'dummy params');