簡體   English   中英

節點 - 等待循環完成?

[英]Node - Wait for loop to finish?

當下面的函數完成並提供數組'albums'中的項目的最終列表時,我希望它調用另一個函數/對列表執行其他操作。

目前它在函數完成之前發布[]並且我知道這是因為異步執行,但我認為Node是線性讀取的,因為它是單線程的?

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
}

您提供給then的回調函數確實是異步執行的,這意味着它只在當前調用堆棧中的其余代碼執行完畢后執行,包括最終的console.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
    });
}

注意:顯然, albums被定義為全局變量。 這不是一個好設計。 每個promise會提供自己的專輯子Promise.all更好,並且Promise.all調用將用於將這些結果連接到局部變量中。 這是如何看起來像:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM