在jQuery中,当我" $。when.apply($,[...])" ...时会发生什么?

时间:2017-12-12 19:23:19

标签: javascript jquery ajax

我正在开发一个JS包,用作大型应用程序的一部分,有时需要在一个组中进行未知数量的API调用,解析所有调用的响应该小组同时进行。

每当处理应该一起处理的多个Ajax调用(使用jQuery)时,使用$.when().done()是有意义的,但因为我不知道提前需要多少个调用,所以我有使用.apply()将所有放入<{em> $.when()来电。

快速注意:我在启动Ajax调用的同一函数中生成了值,我需要将其返回给调用它的函数。因此看起来很奇怪的return [...]部分。 FWIW:我的代码没有被破坏,最终结果完全符合我的要求,但我真的很讨厌使用我还不了解的代码......

有问题的代码如下:

var requestsMap = {
  group1: ["call1"],
  group2: ["call1", "call2"],
  group3: ["call2", "call4", "call6"]
};

var requests = requestsMap[REQUEST_INPUT].map(function(_type) {
  return ajaxCallWrapper(REQUEST_CONFIG, _type);
});

$.when.apply($, requests).done(function() {
  // see comment after code block
});

function ajaxCallWrapper(_config, _type) {
  var customUrl = _config[_type].url;
  var extra1 = "...";
  var extra2 = "...";
  return [$.ajax({
    url: customUrl,
    method: "GET",
    dataType: "json",
    global: false
  }), {
    extra1: extra1,
    extra2: extra2
  }];
}

当我第一次发现$.when()时,我确实注意到使用多个承诺时的不同响应模式(data, textStatus, jqXHR)。结果,我想我可能需要做一些像......

var responses = requests.length === 1 ? [arguments] : arguments;

...当我在.done()中获得响应时,我可以将每个响应作为回调参数循环。但即使只有一个Ajax调用,我仍然可以从第一个回调参数中获取数据,文本状态和XHR对象。

有人可以解释为什么会这样吗?

编辑以澄清。请参阅this JSFiddle以供参考。

最终编辑 - 尝试在我自己的答案中使用相同的代码,但是SO并不喜欢这样......

2 个答案:

答案 0 :(得分:0)

$.when.apply有点难看。 then()done()中的每个参数都是一个数组,数据是数组中的一个元素(我忘记了顺序)

你基本上必须做类似的事情:

$.when.apply($, requests).done(function() {
   [].slice.call(arguments).forEach(function(arg){
      var data = arg[1] // guessing at index here, I forget
   });
   // or
   var allData = [].map.call(arguments) ....
});

由于现代浏览器支持Promise API,我建议使用Promise.all()。所有jQuery deffered api都是在Promises成为常见之前构思出来的,因此$ .when仍然很难看

Promise.all(requests).then(function(resultsArray){
   // resultsArray contains data from each request
});

示例:

const doRequest = (num) => {
  let url = 'http://httpbin.org/get';
  return $.getJSON(url, {id: num }).then(res => res.args)
}

const requests = [1, 2, 3, 4].map(doRequest);

Promise.all(requests).then(res => console.log(res))
.as-console-wrapper {
  max-height: 100%!important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

答案 1 :(得分:0)

Omg ...严肃的facepalm时刻。我道歉,不知道我是怎么错过这个。

回到JSFiddle I created just now

var d1 = $.ajax("/css/light.css");
var d2 = $.ajax("/css/light.css");
var d3 = $.ajax("/css/light.css");
$.when(d1, d2, d3).done(function (v1, v2, v3) {
    console.log("v1:", v1);
    console.log("v2:", v2);
    console.log("v3:", v3);
});

var d4 = $.ajax("/css/light.css");
$.when(d4).done(function (v4a, v4b, v4c) {
    console.log("v4a:", v4a);
    console.log("v4b:", v4b);
    console.log("v4c:", v4c);
});

var d5 = [$.ajax("/css/light.css")];
$.when.apply($, d5).done(function (v5a, v5b, v5c) {
    console.log("v5a:", v5a);
    console.log("v5b:", v5b);
    console.log("v5c:", v5c);
});

var d6 = [$.ajax("/css/light.css"), $.ajax("/css/light.css")];
$.when.apply($, d6).done(function (v6a, v6b, v6c) {
    console.log("v6a:", v6a);
    console.log("v6b:", v6b);
    console.log("v6c:", v6c);
});

在控制台中显示以下输出:

v1: (3) ["", "success", {…}]
v2: (3) ["", "success", {…}]
v3: (3) ["", "success", {…}]
v4a: 
v4b: success
v4c: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
v5a: (3) ["", "success", {…}]
v5b: (3) ["", "success", {…}]
v5c: undefined
v1: (3) ["", "success", {…}]
v2: (3) ["", "success", {…}]
v3: (3) ["", "success", {…}]
v4a: 
v4b: success
v4c: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
v5a: 
v5b: success
v5c: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
v6a: (3) ["", "success", {…}]
v6b: (3) ["", "success", {…}]
v6c: undefined

出于某种原因,我认为我上面的5示例中的代码仍然像6示例中那样返回单个响应。但显然我错了。