等待几个请求完成

时间:2017-11-10 09:47:47

标签: javascript jquery json asynchronous

在我的网页加载中,我必须检索三个JSON(对于loadJSON(),请参阅 PS

$(document).ready(function() {
    loadJSON("JSON1.json",function(json){
        json1 = json:
        console.log("JSON1 loaded");
    });
    loadJSON("JSON2.json",function(json){
        json2 = json:
        console.log("JSON2 loaded");
    });
    loadJSON("JSON3.json",function(json){        
        json3 = json:
        console.log("JSON3 loaded");
    });

    //doing stuff after all three have loaded (PSEUDO:)
    waitTillFinished(doingStuff(json1, json2, json3));
});

然后我需要运行一个结合三个JSON(doingStuff函数)的结果的函数,因此它必须等到所有三个JSON完成。 我虽然有一个功能可以进行主动等待并触发一个回调,例如doingStuff

我该怎么做?

我在这里寻找某种信号量模式。这通常是如何在JS中完成的?

已经尝试过:

jQuery构造:

$( document ).ready(function() {
  $.when(
    loadJSON("JSON1.json",function(json){
        json1 = json;
        console.log("JSON1 loaded");
    }),
    loadJSON("JSON2.json",function(json){
        json2 = json;
        console.log("JSON2 loaded");
    }),
    loadJSON("JSON3.json",function(json){        
        json3 = json;
        console.log("JSON3 loaded");
    })
  ).then(
    doingStuff(json1, json2, json3);
  );
});

这不等待完成的调用。这是完全理解的,因为loadJSON函数已经完成,只有回调还没有被解雇。

使用" status-semaphores"

var status1 = $.getJSON("JSON1.json"[..]); //shortend [..]
var status2 = $.getJSON("JSON2.json"[..]); //shortend [..]
var status3 = $.getJSON("JSON3.json"[..]); //shortend [..]

status1.complete(function(){
  status2.complete(function(){
    status3.complete(doingStuff(json1, json2, json3)
  }
}

这确实有效,但不能扩展。对于两个电话,它会考虑这个解决方案,三个已经有气味。但是,当应用程序增长时,我希望能够获得更多的呼叫。

PS: loadJSON()函数是一个辅助函数,用于加载和记录请求内容:

function loadJSON(requestURL, callback){
  var xobj = new XMLHttpRequest();
  xobj.overrideMimeType("application/json");
  xobj.open('GET', requestURL, true); 
  xobj.onreadystatechange = function(){
      if (xobj.readyState == 4){
          if(xobj.status == 200){
              callback(JSON.parse(xobj.responseText));            
          } else {
              console.error(xobj.statusText);
          }
      }
  }
  xobj.onerror = function(e){
      console.error(xobj.statusText);
  }
  xobj.send();
}

1 个答案:

答案 0 :(得分:3)

使用$.when的代码可以使用,如果 loadJSON返回一个承诺/延期,就像jQuery' getJSON那样。所以:

$( document ).ready(function() {
  $.when(
    $.getJSON("JSON1.json"),
    $.getJSON("JSON2.json"),
    $.getJSON("JSON3.json")
  ).then(function(data1, data2, data3) { // Note naming, once they're parsed (which
    doingStuff(data1, data2, data3);     // getJSON does), they're not JSON anymore
  });
});

或实际上,如果doingStuff按照我们将调用传递给$.when的顺序获取三个参数,则我们不需要包装函数:

$( document ).ready(function() {
  $.when(
    $.getJSON("JSON1.json"),
    $.getJSON("JSON2.json"),
    $.getJSON("JSON3.json")
  ).then(doingStuff);
});

注意我已使用then代替done。不同寻常的是,then回调将针对每个结果使用离散参数进行调用(而普通then仅使用一个参数调用其回调)。请注意,如果您改为使用done,则会获得三个离散参数,但它们会数组,其中每个数组都包含数据,textStatus和jqXHR对象来自$.getJSON电话。

或者我们可以使用Promise.all(在任何主要的现代浏览器上):

$( document ).ready(function() {
  Promise.all([
    $.getJSON("JSON1.json"),
    $.getJSON("JSON2.json"),
    $.getJSON("JSON3.json")
  ]).then(function(results) {
    doingStuff(results[0], results[1], results[2]);
  });
});

注意我们将promises作为数组传递,然后返回一个数组。在ES2015 +中,我们可以在then回调的参数列表中使用解构:

$( document ).ready(function() {
  Promise.all([
    $.getJSON("JSON1.json"),
    $.getJSON("JSON2.json"),
    $.getJSON("JSON3.json")
  ]).then(([data1, data2, data3]) => {
    doingStuff(data1, data2, data3);
  });
});