我需要一些帮助来处理JavaScript中的异步调用。我有一个for循环,每个循环调用一个异步HttpRequest,并将其响应添加到一个数组。我希望程序等到所有异步调用完成后再继续jQuery(仅用于DOM操作)。我已经搜索了很多解决方案,但是如果没有大量更改代码或依赖jQuery,没有一个真正有效。
function httpGet(theUrl, callback) {
var xmlRequest = new XMLHttpRequest();
xmlRequest.onreadystatechange = function() {
if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
callback(xmlRequest.responseText);
}
}
xmlRequest.open("GET", theUrl, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.setRequestHeader("Accept", "application/json");
xmlRequest.send(null);
}
$(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
var data = [];
(function(urls, data) {
urls.forEach(function(url) {
function(resolve, reject) {
httpGet(url, function(response) {
data.push(JSON.parse(response));
})
};
})
})(urls, data);
// Continue after all async calls are finished
})
更新:使用Promise编辑,但仍然无法正常工作,也许我做错了。
function httpGet(theUrl, callback) {
return new Promise(function(resolve, reject) {
var xmlRequest = new XMLHttpRequest();
xmlRequest.onreadystatechange = function() {
if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
callback(xmlRequest.responseText);
}
}
xmlRequest.open("GET", theUrl, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.setRequestHeader("Accept", "application/json");
xmlRequest.send(null);
})
}
$(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
var data = [];
var promises = [];
(function(urls, data) {
urls.forEach(function(url) {
var promise = httpGet(url, function(response) {
data.push(JSON.parse(response));
});
promises.push(promise);
})
Promise.all(promises).then(function() {
console.log(data);
})
})(urls, data);
})
答案 0 :(得分:1)
使用promises,您不应使用callback
参数。请改为从承诺中调用resolve
/ reject
函数。
不是将回调传递给调用,而是使用.then
处理程序中的promise结果链接您想要执行的操作。
function httpGet(theUrl) {
return new Promise(function(resolve, reject) {
var xmlRequest = new XMLHttpRequest();
xmlRequest.onreadystatechange = function() {
if (xmlRequest.readyState == 4) {
if (xmlRequest.status == 200)
resolve(xmlRequest.responseText);
// ^^^^^^^
else
reject(new Error(xmlRequest.statusText)); // or something
}
}
xmlRequest.open("GET", theUrl, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.setRequestHeader("Accept", "application/json");
xmlRequest.send(null);
});
}
$(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
var promises = urls.map(function(url) {
// ^^^ simpler than forEach+push
var promise = httpGet(url); // <-- no callback
return promise.then(JSON.parse);
});
Promise.all(promises).then(function(data) {
// ^^^^
console.log(data);
});
})
答案 1 :(得分:0)
由于您使用的是jQuery,因此您可以使用Deferred Object链接承诺。
收集所有承诺并使用$.when
与传播运营商等待所有承诺解决。在解决所有ajax请求后,您可以使用then
运行函数。
ES5示例
$(document).ready(function () {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];
var urls = channels.map(function (x) {
return "https://api.twitch.tv/kraken/channels/" + x;
});
var data = [];
var promises = urls.map(function (url) {
return $.get(url).then(function (response) {
data.push(response);
});
});
$.when.apply($, promises).then(function () {
console.log('done', data);
});
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
ES6示例
$(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
var data = [];
var promises = urls.map((url) => $.get(url).then((response) => {
data.push(response);
}));
$.when(...promises).then(function() {
console.log('done', data);
});
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
答案 2 :(得分:0)
不能通过将ajax请求的计数保持为变量来完成:
var urls_count, data_count = 0;
function httpGet(theUrl, callback, onComplete) {
var xmlRequest = new XMLHttpRequest();
xmlRequest.onreadystatechange = function() {
if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
callback(xmlRequest.responseText);
}
if(xmlRequest.readyState == 4){
data_count += 1
if(urls_count == data_count){
//this is called when all ajax calls complete
onComplete();
}
}
}
xmlRequest.open("GET", theUrl, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.setRequestHeader("Accept", "application/json");
xmlRequest.send(null);
}
$(document).ready(function() {
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
var data = [];
urls_count = urls.length;
var onComplete = function(){
//your code after all ajax completes.
}
(function(urls, data) {
urls.forEach(function(url) {
function(resolve, reject) {
httpGet(url, function(response) {
data.push(JSON.parse(response));
}, onComplete)
};
})
})(urls, data);
})