Ajax API 嵌套循环调用需要按顺序执行

Ajax API calls in nested loop need to be executed in order

假设您有一个场景需要在页面的文本区域中创建 .csv 输出...

所以我有 2 个数组,我循环嵌套在另一个数组中。嵌套循环的结果是通过 ajax 调用的查询...我需要将 ajax 调用的结果附加到文本区域中。

我的问题是如何按照请求的顺序打印出结果(基本上是查询数组中的顺序)

//example array to loop.
var outerQuery= ['A', 'B', 'C', 'D', 'E', 'F'];
var outerQueryLegth = outerQuery.length;
var innerQuery= ['1', '2', '3', '4', '5', '6'];
var innerQueryLegth = innerQuery.length;

//the textarea where im going to print the results in order later to open in excel as a .csv file
var $csvText= $('#some-text-area');

//outter loop
$.each(outerQuery, function(outerIndex, outer){
      //Print the row
      $csvText.append('Row' + outer +'\r\n\r\n');
      
      //Nested inner loop (that should execute in order regarless or the time of the api call)
      innerQuery.reduce(function(innerCallback, inner, innerIndex){
        return innerCallback.then(function(){
         return GoogleAnalyticsAPI(inner).then(function(response){
            $csvText.append(response.column1 +',');
          });
        });//end inner callback
      },Promise.resolve());
});

function GoogleAnalyticsAPI(val) {
 return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({column1: val });
    }, Math.floor((Math.random() * 1000) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>

正如您在代码段中看到的结果 运行 非常奇怪 理想情况下,它们应该像这样打印:

RowA
1,2,3,4,5,6
RowB
1,2,3,4,5,6
RowC
1,2,3,4,5,6
.
.
.

我从 那里得到的 innerQuery.reduce 这真的很有帮助,感谢 @jfriend00

谢谢大家

您可以使用 .queue(), .promise() 到 return 函数,顺序对应于数组中的索引

//example array to loop.
var outerQuery = ['A', 'B', 'C', 'D', 'E', 'F'];
var outerQueryLegth = outerQuery.length;
var innerQuery = ['1', '2', '3', '4', '5', '6'];
var innerQueryLegth = innerQuery.length;
var $csvText = $('#some-text-area');

// create `"outerQuery"` queue
$csvText.queue("outerQuery", $.map(outerQuery, function(outer, index) {
  return function(next) {
    $(this).append((index > 0 ? '\r\n\r\n' : "") 
                    + 'Row' + outer + '\r\n\r\n')
    // create `"innerQuery"` queue
    .queue("innerQueue", $.map(innerQuery, function(inner, innerIndex) {
        return function(_next) {
          return GoogleAnalyticsAPI(inner).then(function(response) {
            $csvText.append(response.column1 + ',');
            // call `_next` function in `"innerQueue"`
          }).then(_next); 
        }
      })).dequeue("innerQueue").promise("innerQueue")
    // call `next` function in `"outerQueue"`
    // when all functions in current `innerIndex`
    // of `innerQueue` array , `"innerQueue"` completes
    .then(next)
  }
})).dequeue("outerQuery");

function GoogleAnalyticsAPI(val) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({
        column1: val
      });
    }, Math.floor((Math.random() * 1000) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>

您可以继续使用在 的内部 .reduce() 循环中使用的相同逻辑,并将其应用于外部循环。此外,您可以使用普通 Javascript 概念进行同步。

这样做的关键是来自先前答案的内部 .reduce() 循环 returns 只有当内部循环中的所有链式异步操作完成时才会解决的承诺。您可以像这样使用该承诺来控制和同步外循环:

//example array to loop.
var outerQuery= ['A', 'B', 'C', 'D', 'E', 'F'];
var innerQuery= ['1', '2', '3', '4', '5', '6'];

//the textarea where im going to print the results in order later to open in excel as a .csv file
var $csvText= $('#some-text-area');

//outer loop
outerQuery.reduce(function(outerP, outerItem) {
    return outerP.then(function() {
        //Print the row
        $csvText.append('Row' + outerItem +'\r\n');
        return innerQuery.reduce(function(innerP, inner, innerIndex){
            return innerP.then(function(){
                return GoogleAnalyticsAPI(inner).then(function(response){
                $csvText.append(response.column1 +',');
              });
            });
        }, Promise.resolve()).then(function() {
            $csvText.append('\r\n\r\n');
        });      
    });
}, Promise.resolve());

function GoogleAnalyticsAPI(val) {
 return new Promise(function(resolve) {
    setTimeout(function() {
      resolve({column1: val });
    }, Math.floor((Math.random() * 500) + 1));
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<textarea id="some-text-area" rows="20" cols="30"></textarea>