Javascript回调无效,在ajax请求完成之前运行回调

时间:2016-07-09 13:46:58

标签: javascript jquery

我想了解回调。我有这个代码,可以从控制台运行。我想从阵列用户那里获取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');
    });
})();

3 个答案:

答案 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');
    });
})();