簡體   English   中英

JavaScript回調無法正常運行,在ajax請求完成之前運行回調

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM