我正在尝试创建一个使用twitch.tv api来查看twitch streamers数组的查看器,然后发布哪些用户当前在线以及他们正在流媒体什么。我在弄清楚如何使用回调的异步特性方面遇到了一些严重的麻烦。

我想遍历数组中每个抽搐用户的api调用一次。他们全部归还后,我希望能够对它们进行排序并按特定条件列出它们。

经过大量研究,我尝试使用promises来做到这一点。但是我仍然无法弄清楚这一点。

我已经使用了这个问题:How can I wait for set of asynchronous callback functions?和这个问题:How do I return the response from an asynchronous call?作为准则,但是显然我仍然缺少一些重要的东西。我已经发布了代码的相关部分。如果有任何帮助/朝正确的方向发展,我将不胜感激。

 $(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff","ESL_SC2", "brunofin"];
var test = [];
function getData(){
    var promises = [];
    for (var i = 0; i < channels.length; i++) {
        promises.push($.getJSON('https://api.twitch.tv/kraken/streams/'+channels[i]+'?callback=?', function(data) {}));
    }
    $.when.apply($, promises).then(function() {
        // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0]
        // you can process it here
        for(var j=0; j<promises.length; j++){
            //console.log(promises[j].responseJSON);
            test.push(promises[j]);
        }
    }, function() {
        // error occurred
        conole.log("get data error");
    });
}

    getData();
    console.log("do I have data?: ");
    for(var j=0; j<test.length; j++){
            console.log(test[j].responseJSON); //This is empty and where I need the data!
        }


});

最佳答案

在代码中,您要调用getData(),然后在下一行上遍历test数组。这是在事件循环的同一过程中发生的,因此您不会给诺言任何实际运行其逻辑并解决任何问题的机会。逐行执行是同步的,在两者之间无法执行任何操作。

一种解决方案是从getData函数返回一个承诺,并等待其解决。

由于您正在使用Promises,因此您也不需要任何$getJSON函数的回调。

$(document).ready(function() {
  var channels = [
    "freecodecamp", "storbeck", "terakilobyte", "habathcx",
    "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff",
    "ESL_SC2", "brunofin"
  ];

  var test = [];

  function getData() {
    var promises = [];
    for (var i = 0; i < channels.length; i++) {
      promises.push(
        $.getJSON(
          'https://api.twitch.tv/kraken/streams/'+channels[i]+'?callback=?'
        )
      );
    }

    return $.when.apply($, promises).then(function() {
      for(var j=0; j<promises.length; j++){
        test.push(promises[j]);
      }
    });
  }

  getData().then(function() {
    console.log("do I have data?: ");
    for(var j=0; j<test.length; j++) {
       console.log(test[j].responseJSON);
     }
  });
});




让我也建议重构此代码。这是一个有趣的问题,是在JavaScript中常做的事情,我想通过此示例演示如何使用Promise数组。

每个异步操作都是独立运行的,您的直觉是正确的:您需要一些其他工具才能将所有结果汇总在一起。

使用promise时,此工具为Promise.all。实际上,jQuery的$.when与之类似,尽管我发现Promise.all由于其输入和返回类型而更易于使用。它也是标准JavaScript,可在所有现代浏览器中使用。

当许多个人承诺得到解决时,Promise.all可用于运行某些逻辑。形式上,Promise.all接受一个诺言数组并返回一个诺言,当所有输入的诺言得到解决(或其中一个拒绝)时,该诺言就解决。它解析为单个诺言所解决的一系列已解决的值。

由于Promise.all需要一个数组,因此可以很好地与mapfilter之类的数组方法配合使用。

function getStreams(channels) {
  // Transform an array of channel names into an array of Promises
  // representing the asynchronous action of getting the info
  // about each channel.
  const promises = channels.map(
    channel => $.getJSON(
      'https://api.twitch.tv/kraken/streams/'+channel+'?callback=?'
    )
  );

  // Return a new promise which will resolve when *all* channels
  // have been queried.
  return Promise.all(promises);
}

const channels = [
  "freecodecamp", "storbeck", "terakilobyte", "habathcx",
  "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff",
  "ESL_SC2", "brunofin"
];

getStreams(channels).then(
  // infos is an array of resolved data about the channels
  infos => infos.forEach(
    info => console.log(info)
  )
);

10-07 19:10
查看更多