我想了解回调。我有这个代码,可以从控制台运行。我想从阵列用户那里获取github配置文件,当它们全部加载(在控制台上显示)时,我想在控制台上显示“已完成”。我正在使用回调,我认为这就是我的问题所在。
不幸的是,'Finished'显示在控制台上,然后是来自github的数据。显然它是异步的,并且回调不起作用。我该怎么办?
这是输出
VM134355:24 Finished
undefined
VM134355:4 Object {login: "Amichai", id: 313874, avatar_url: "https://avatars.githubusercontent.com/u/313874?v=3", gravatar_id: "", url: "https://api.github.com/users/Amichai"…}
VM134355:5 Amichai has 65 public repositories!
VM134355:4 Object {login: "adamwiggins", id: 177, avatar_url: "https://avatars.githubusercontent.com/u/177?v=3", gravatar_id: "", url: "https://api.github.com/users/adamwiggins"…}
VM134355:5 Adam Wiggins has 94 public repositories!
VM134355:4 Object {login: "fzzr-", id: 888526, avatar_url: "https://avatars.githubusercontent.com/u/888526?v=3", gravatar_id: "", url: "https://api.github.com/users/fzzr-"…}
VM134355:5 Alexander "FIZZΞR" Koz. has 129 public repositories!
代码是
function makeRequest(url,index,array){
function printRepoCount() {
var responseObj = JSON.parse(this.responseText);
console.log(responseObj);
console.log(responseObj.name + " has " + responseObj.public_repos + " public repositories!");
}
var request = new XMLHttpRequest();
request.onload = printRepoCount;
request.open('get', url, true);
request.send();
}
function loadPages(files, _callback) {
files.forEach(makeRequest);
_callback();
}
var users = ['https://api.github.com/users/Amichai',
'https://api.github.com/users/adamwiggins',
'https://api.github.com/users/fzzr-'];
(function runFunction(){
loadPages(users, function() {
console.log('Finished');
});
})();
答案 0 :(得分:1)
您可能希望查看Promises,但如果您更愿意坚持使用代码,则可以使用计数器包装makeRequest()方法,如下所示:
function makeRequest(url,index,array){
function printRepoCount() {
var responseObj = JSON.parse(this.responseText);
console.log(responseObj);
console.log(responseObj.name + " has " + responseObj.public_repos + " public repositories!");
}
var request = new XMLHttpRequest();
request.onload = printRepoCount;
request.open('get', url, true);
request.send();
// Don't forget to return the request!
return request;
}
function loadPages(files, _callback) {
var files_count = files.length,
files_loaded = 0;
files.forEach(function(file) {
var request = makeRequest(file);
var req_onload = request.onload;
request.onload = function(t) {
req_onload.bind(this)(t);
files_loaded++;
if (files_loaded === files_count) {
_callback();
}
}
});
}
我更改loadPages
以更改从onload
返回的请求对象的makeRequest
方法 - 首先我将原始onload保存在req_onload
中,然后我将其替换为files_loaded
触发原始方法(在事件本身的上下文中)然后递增计数器(files_loaded
)的方法。当files_count
到达_callback
时,它会触发您的testList<-list(list(a=1,b=2,c=3),c(1,2),list(a=1,b=2,c=0))
方法。
您可以在此fiddle
中查看答案 1 :(得分:0)
使用jQuery及其Deferred
对象从每个AJAX请求中获取promise。然后等待所有人使用$.when()
完成并调用回调。
function loadPages(files, _callback) {
var promises = $.map(files, function(file) {
return $.getJSON(file, function(responseObj) {
console.log(responseObj);
console.log(responseObj.name + " has " + responseObj.public_repos + " public repositories!");
})
});
$.when.apply(null, promises).then(_callback);
}
如果您不想使用jQuery(但为什么要将它放在标签中?),使用Fetch API的结构将类似,因为它也会返回一个承诺。您可以使用Promise.all()
等待所有这些内容完成。
答案 2 :(得分:0)
基本上javascript遵循单线程同步执行。
所以基本上它逐行读取代码并执行它。 AJAX请求仅通过javascript同步考虑,但它的响应不在javascript手中。这可能需要一些时间,具体取决于很多因素(互联网速度,API等)。
所以基本上你需要在获得API的响应后执行回调函数
虽然在这种情况下非常推荐使用promises,但你仍然可以看到理解回调的解决方案
您可以这样做:
var users = ['https://api.github.com/users/Amichai',
'https://api.github.com/users/adamwiggins',
'https://api.github.com/users/fzzr-'];
function makeRequest(url, _callback){
var counter = 0
function printRepoCount() {
counter++;
var responseObj = JSON.parse(this.responseText);
console.log(responseObj);
console.log(responseObj.name + " has " + responseObj.public_repos + " public repositories!");
if(counter == users.length){
_callback(); // execute the callback after the response from the ajax
}
request is displayed.
}
var request = new XMLHttpRequest();
request.onload = printRepoCount;
request.open('get', url, true);
request.send();
}
function loadPages(files, _callback) {
files.forEach(makeRequest, _callback);
}
(function runFunction(){
loadPages(users, function() {
console.log('Finished');
});
})();