![](/img/trans.png)
[英]How do I wait until an asynchronous process inside a loop is finished before exiting the loop?
[英]How can I wait until Asynchronous callbacks are finished before using the data retrieved?
我正在尝试创建一个查看器,该查看器使用 twitch.tv api 检查一系列 twitch 流媒体,然后发布哪些用户当前在线以及他们正在流式传输什么。 我在弄清楚如何处理回调的异步性质时遇到了一些严重的问题。
我想为数组中的每个 twitch 用户循环一次 api 调用。 在他们全部返回后,我希望能够对它们进行分类并按照特定标准的顺序列出它们。
经过大量研究,我正在尝试使用承诺来做到这一点。 但是,我仍然无法弄清楚这一点。
我用过这个问题: 如何等待一组异步回调函数? 和这个问题: 如何从异步调用返回响应? 作为指导,但显然我仍然缺少一些重要的东西。 我已经发布了我的代码的相关部分。 我将不胜感激任何帮助/推动我所缺少的东西的正确方向。
$(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
函数返回一个 promise 并等待它解析。
由于您正在使用 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.all
,这个工具是Promise.all
。 事实上,jQuery 的$.when
Promise.all
是类似的,尽管我发现Promise.all
由于其输入和返回类型而更容易使用。 它也是标准的 JavaScript,可在所有现代浏览器中使用。
Promise.all
可用于在多个单独的承诺解决时运行一些逻辑。 正式地, Promise.all
接受一组承诺并返回一个承诺,当所有输入承诺解决(或其中一个拒绝)时,该承诺会解决。 它解析为一组已解析的值,各个承诺解析为这些值。
由于Promise.all
接受一个数组,因此它适用于map
和filter
等数组方法。
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)
)
);
异步正是这个名字所暗示的。
您只能在 when 回调的第一个函数中访问该数据。 由于数据在此之前不存在于您的页面上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.