Javascript 节点-等待循环完成?

Javascript 节点-等待循环完成?,javascript,node.js,for-loop,asynchronous,callback,Javascript,Node.js,For Loop,Asynchronous,Callback,当下面的函数完成并提供数组“albums”中项目的最终列表时,我希望它调用另一个函数/使用该列表执行其他操作 目前它在函数完成之前发布[],我知道这是因为异步执行,但我认为节点是线性读取的,因为它是单线程的 function getAlbumsTotal(list, params){ for(var i = 0; i<list.length; i++){ api.getArtistAlbums(list[i], params).then(function(data)

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

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

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
}
函数getAlbumsTotal(列表,参数){
对于(var i=0;i您提供给
的回调函数,则
确实是异步执行的,这意味着它仅在当前调用堆栈中的其余代码(包括最终的
控制台.log)执行完毕后执行

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

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
    });
}

如果你想在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');
函数getArtistAlbums(艺术家,参数){
变量artistAlbums={
“Aphex Twin”:[“Syro”,“Drukq”],
“Metallica”:[“全部杀死”、“重新加载”]
};
返回新承诺(功能(履行、拒绝){
完成(艺术家);
});
}
函数getAlbumsTotal(列表,参数){
var-listCount=0;

对于(var i=0;iIs),这是最优雅的方法吗?如果我不使用呢。然后,使用类似这样的函数来代替
函数getAlbumsTotal(list,params){for(var i=0;异步性仍然存在:您仍然有一个回调函数,它在当前运行的任何其他函数之后执行。因此,事实上,您最好使用承诺,因为像
Promise.all这样的东西将所有这些结合在一起。否则,您将不得不在最后一次调用c时开始计数allback。我用一个版本扩展了我的答案,这个版本使用一个局部变量
albums
,而不是一个全局变量,它(取决于你对它做了什么),将是更好的设计。
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');