【问题标题】:Perform a set of recursive HTTP GET calls, and wait for them all执行一组递归 HTTP GET 调用,并等待所有调用
【发布时间】:2017-12-29 12:37:33
【问题描述】:

我有一个 REST 服务,提供一个“Json”对象列表,每个对象都可能具有指向其自身类的另一个资源的链接。从一个特定的开始,我需要全部获取它们,执行递归 http 调用。 于是我写了:

var steps = [];
var recursiveLookup = function(processId) {
  return $.ajax({
    url: SERVER_URL + processId,
    success: function (activity) {
      // Activity has a set of json objects called steps
      var rtn = activity.path.map(step => {
        if (step.type != "Node") {
          steps.push(step);
        } else {
          return recursiveLookup(step.subProcessIntanceId);
        }
      }).filter(a => a != undefined);
      return rtn;
    }
  });
}

这会正确地将所有对象加载到全局步骤 var 中。 我需要确保方法已经完成,所以我写道:

var promises = recursiveLookup(processId);
Promise.all(promises).then(function () {
   console.log(steps);
});

但它不起作用,因为“recursiveLookup”正在返回 $.ajax 的承诺,而不是假装使用成功方法返回的承诺集。

此外,是否可以将步骤作为返回值从“recursiveLookup”方法中获取,而不是将其用作全局变量?

【问题讨论】:

  • 添加异步:false
  • 是我还是你的函数有 2 个返回值?我的意思是你首先返回 rtn,然后尝试返回 ajax 本身。
  • “此外,是否可以将步骤作为返回值从 'recursiveLookup' 方法中获取,而不是将其用作全局变量?”您可以使用成功: $.proxy(function(activity) { #code }, steps)
  • 你的服务器不能在一个请求中产生整个递归树响应吗?

标签: javascript jquery


【解决方案1】:

嵌套递归不在我的舒适区,但也许这会起作用:

var recursiveLookup = function(processId,steps=[]) {
  return $.ajax({
    url: SERVER_URL + processId,
  })
  .then(
    function (activity) {
      // Activity has a set of json objects called steps
      steps = steps.concat(
        activity.path.filter(
          step => step.type !== "Node"
        )
      );
      return Promise.all(
        activity.path.filter(
          step => step.type === "Node"
        )
        .map(
          step=>
            recursiveLookup(step.subProcessIntanceId,steps)
        )
      ).then(
        result=>steps.concat(result)
      )
    }
  );
}

为了使尾调用优化发挥作用,函数所做的最后一件事应该是调用递归函数,但我认为在承诺链中这并不重要。

【讨论】:

  • 看起来不错,但是 concat 返回一个新数组,所以我应该执行 steps = steps.concat(...),这样做不会改变接收到的数组参数...
  • activity.path.filter( step => step.type !== "Node" ).map( s=> steps.push(s) );
【解决方案2】:

如果您想使用 Promise,则不应使用 success 参数。相反,您希望返回一个 Promise,并希望使用 then 将 Promise 的结果转换为不同的东西,甚至可能是另一个 Promise。

function request(page) {    
…
// return the AJAX promise
return $.ajax({
    url: '/echo/json/',
    method: 'POST',
    dataType: 'json',
    data: {
        delay: 1,
        json: JSON.stringify(ret)
    }
 });
}

function requestOddsFrom(page, items) {
return request(page).then(function(data){
    if (data.currentPage > data.totalPage) {
        return items;
    } else {
        var filtered = data.items.filter(function(el){ return el%2 == 1; });
        return requestOddsFrom(data.currentPage + 1, items.concat(filtered));
    }
 });
}

function requestAll(){
return requestOddsFrom(1, []);
}

 requestAll().then(function(items) {
   console.dir(items);
});

更多信息jQuery Recursive AJAX Call Promise

How do I return the response from an asynchronous call?

【讨论】:

  • 这太荒谬了。 async:false 是一种糟糕的做法,已被弃用。使用它会导致开发工具控制台中的警告永远不要使用它
  • 这取决于你的需要伙计。并非每种语言都是完美的,您需要根据需要对其进行修改
  • 使用不推荐使用的方法不是这样做的方法。尤其是在递归调用中!
  • 抱歉,Negi,确实是这样。也许在 Node 中你可以侥幸逃脱,但浏览器中的同步 Web 请求会挂掉一切。你可以查看here 了解为什么 ES 使用回调或承诺进行异步操作(或不立即返回值的操作,如网络请求)
猜你喜欢
  • 2023-04-08
  • 2018-12-27
  • 2022-01-27
  • 2021-05-12
  • 2014-12-22
  • 2020-11-03
  • 1970-01-01
  • 2022-09-28
  • 1970-01-01
相关资源
最近更新 更多