【问题标题】:Jquery Defer & Each LoopJquery Defer & 每个循环
【发布时间】:2017-06-26 15:57:27
【问题描述】:

我对 JSON 和 Deferrers 有点陌生,所以很抱歉答案很明显。

我正在与 pokeapi.co 合作,我正在尝试使用 getJSON 提取各种 pokemon 的详细信息。我创建了一个函数,它接受一个 URL 数组,运行一个 getJSON 函数从 URL 中提取数据,迭代数据并将其推送到一个数组中。我正在尝试使用 defer 对象并承诺确定所有操作何时完成,以便我可以在另一个函数中使用数据。不幸的是,我似乎做错了什么。

var url = [
  "http://pokeapi.co/api/v2/pokemon/1/",
  "http://pokeapi.co/api/v2/pokemon/2/"
];

function getPokemonDetails(url){
  var def = $.Deferred();
  var promises = [];
  var pokemon;
  $.each(url, function(i, index){
    var deferred = $.Deferred();
    $.getJSON(index, function(data){
      pokemon = [data.name, data.stats];
      var abilityURLs = [];
      $.each(data.abilities, function(a, abilities){
        abilityURLs.push(abilities.ability.url)
      });

      pokemon.push(abilityURLs);
      deferred.resolve(pokemon);
    }); //End getJSON

    deferred.done(function(data){
      promises.push(data);
      console.log(promises);
    })// End Deferred
  }); //End Each

  $.when(...promises).done(function(){
    console.log(arguments.length);
  });
}

getPokemonDetails(url);

目前,当 console.log 运行时,我预计 promises 数组的长度为 2,但此时它返回 0。我不确定我到底哪里出错了。

【问题讨论】:

  • 在创建 promise 数组时,.map 通常是正确的工具。您立即需要一系列承诺,这是您问题的一部分;在承诺完成之前,您不会推送到数组,这是不正确的。
  • 并且当使用$.getJSON 时,在它们周围创建自己的 jQuery 延迟对象通常是一种反模式
  • 另外,你不需要$.Deferred,$.getJSON 已经返回了一个承诺。

标签: jquery promise getjson jquery-deferred


【解决方案1】:

首先,不要使用$.each 和推送,因为你有一个从源数组到目标数组的1:1 映射,你应该使用Array.prototype.map。

其次,由于$.getJSON 已经返回了$.Deferred(),因此完全没有必要自己创建一个。

因此,如果我正确地遵循了您当前的代码,则可以将其完全替换为:

function getPokemonDetails(url_list) {
    return $.when(... url_list.map(url =>
        $.getJSON(url).then(
            data => [ data.name, data.stats, [
                data.abilities.map(ability => ability.ability.url)
            ]]
        )
    ));
}

内部.then 调用获取从每个 AJAX 调用返回的数据,并返回一个解析为名称数组、统计信息和嵌套能力数组的承诺。

对于它的价值,我可能会将其拆分为两个函数 - 一个处理单个 URL,另一个处理多个 URL:

const getPokemonDetails = url => $.getJSON(url).then(
    data => [ data.name, data.stats, [
                data.abilities.map(ability => ability.ability.url)
            ]]);

const getMultiPokemonDetails = list => $.when(...list.map(getPokemonDetails));

【讨论】:

  • 嗨,Alnitak,感谢您的回复。解决方案中 url_list 之前的三个点是数组扩展运算符吗?我认为他们必须就在阵列旁边?
  • @tcherokee 是的,它是一个数组扩展运算符,空格是合法的
  • 嗨 Alnitak,很抱歉有一段时间没有回复,我一直在做一些研究和阅读以完全理解您的解决方案。它使用了一些我还没有学过的想法(例如箭头函数)。所以我有几个问题。一,由于某种原因,上面的解决方案只显示一个结果,即使两个 URL 被传递到 url_list 中。我不确定为什么。第二个问题,如果我扩展上述功能(即url_list.map(function(){...}) 而不是url_list.map(url=>...,它将停止工作。我希望你知道为什么?
  • @tcherokee 返回的承诺应该给出两个结果getPokemonDetails(list).then(function(result1, result2) { ... }。 ($.when 不会生成数组)。至于箭头函数,不要忘记单表达式箭头函数有一个隐含的return,因此如果不使用该语法,您必须显式 return 获得所需的结果。
  • 我认为我拥有应有的一切。我将所有工作数据添加到笔中,以便您查看。 codepen.io/tcherokee/pen/jwZPej
猜你喜欢
  • 2019-07-21
  • 2016-12-21
  • 1970-01-01
  • 2017-11-25
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-06
相关资源
最近更新 更多