[英]Javascript callback not working, running callback before ajax request has finished
我試圖理解回調。 我有這段代碼,可以從控制台運行。 我想從陣列用戶那里獲取github配置文件,當他們全部加載后(顯示在控制台上),我想在控制台上顯示“完成”。 我正在使用回調,我認為這是我的問題所在。
不幸的是,控制台上顯示了“完成”,然后顯示了來自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');
});
})();
您可能想研究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
方法。
你可以在這個小提琴中檢查一下
使用jQuery及其Deferred
對象從每個AJAX請求中獲取承諾。 然后等待它們全部以$.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。 您將使用Promise.all()
等待它們全部完成。
基本上,javascript遵循單線程同步執行。
因此,基本上,它逐行讀取代碼並執行它。 javascript僅同步考慮AJAX請求,但它的響應不在javascript手中。 這可能需要一些時間,具體取決於許多因素(互聯網速度,API等)
因此,基本上,您需要在收到API的響應后執行回調函數
盡管在這種情況下非常推薦使用Promise,但是仍然可以看到理解回調的解決方案
您可以執行以下操作:
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');
});
})();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.