首页 > 解决方案 > 嵌套 getJSON 调用后输出序列不正确

问题描述

在我的项目中,我需要rest API拨打电话并获取一个JSON数组作为响应。

每个数组元素将包含一个项目“密钥”(项目密钥)。响应示例在这里

现在我想遍历这个数组,获取项目密钥,然后进行另一个 REST 调用以获取每个项目的详细信息。

我正在使用下面的代码来执行此操作,但最终输出并未按预期进行。

var myOutput = [];
$.when (
    $.getJSON(projectListURL, function (data) {
        var compArr = data.components;
        for (i=0 ; i<compArr.length ; i++) {
            var projectKey = compArr[i].key;
            var projectName = compArr[i].name;

            var myURL = "http://myserver.com/projectdetails?projectkey=" + projectKey;
            $.getJSON(myURL, function (data) {

            }).then (function (data){
                console.log("myURL:" + myURL);
                console.log("name:" + projectName);
                var item = {};
                item["name"] = projectName;
                item["status"] = data.projectStatus.status;
                console.log(item);
                myOutput.push(item);
            });
        }
    })
).done (function () {
    console.log(myOutput);
});

我希望 myOutput 类似于:

[
    {name: "BaseProj", status: "OK"},
    {name: "Sudoku Project", status: "ERROR"},
    {name: "My Project", status: "WARN"}
]

但我得到:

[
    {name: "My Project", status: "OK"},
    {name: "My Project", status: "ERROR"},
    {name: "My Project", status: "WARN"}
]

请提出正确的方法应该是什么?

谢谢你

标签: javascriptjqueryhtmljson

解决方案


问题是因为外部循环在所有 AJAX 请求完成并且它们的回调运行之前完成。因此projectKeyprojectNamemyURL变量都保存最后一次迭代的值。

要解决此问题,您可以在内部调用周围使用闭包来维护您传入的变量的范围:

var myOutput = [];
$.when(
  $.getJSON(projectListURL, function(data) {
    var compArr = data.components;
    for (i = 0; i < compArr.length; i++) {
      var projectKey = compArr[i].key;
      var projectName = compArr[i].name;
      var myURL = "http://myserver.com/projectdetails?projectkey=" + projectKey;

      (function(url, name) {
        $.getJSON(url, function(data) {

        }).then(function(data) {
          console.log("myURL:" + url);
          console.log("name:" + name);
          var item = {
            name: name,
            status: data.projectStatus.status
          };
          console.log(item);
          myOutput.push(item);
        });
      })(myURL, projectName);
    }
  })
).done(function() {
  console.log(myOutput);
});

或者,您可以避免使用闭包并使用let关键字而不是定义变量var,但请注意,这在 < IE11 中不起作用。

最后,请注意,在任何一种情况下,您都可以删除调用的回调处理函数,$.getJSON因为您不使用它,例如:

$.getJSON(myURL).then(function(data) {
  // code...
});

推荐阅读