【问题标题】:Get second call's response from first call's promise从第一个电话的承诺中获取第二个电话的响应
【发布时间】:2016-05-12 21:20:19
【问题描述】:
getAjaxPromise(myUrl, true,   myType, myContentType, mySuccessFunction, myFailureFunction, myData, true)     .then(function(data)
 { 
//Do something with the data returned form second Ajax call. 
//But data returned here is from first ajax. 
});


self.getAjaxPromise = function(url, async, type,  contentType, successCallback, errorCallback, data, isSecureCall) 
{
  if (isSecureCall) {
    var tokenPromise = getTokenPromiseFromServer(); //Another Ajax call to get latest token from service
    tokenPromise.then(function(tokenData) {  //This then runs fine
      return $.ajax({
        beforeSend:  function(request) {
          request.setRequestHeader("authKey", tokenData.key);
        },
        url: url,
        async: async,
        type: type,
        contentType: contentType,
        success:
        successCallback,
        error: errorCallback,
        data: JSON.stringify(data)
      });
    });
  } else { //Just one ajax call 
    return $.ajax({
      beforeSend:   function(request) {
        request.setRequestHeader("authKey"      , "anonymous");
      },
      url: url,
      async: async,
      type: type,
      contentType: contentType,
      success: successCallback,
      error: errorCallback,
      data: JSON.stringify(data)
    });
  }
};

在上面的代码中,当我编写 .then() 时,我得到了第一个 ajax 调用的响应,我不需要第一个 ajax 的响应,而是我想在第一个 ajax 的 then() 中获取 ajax 的响应.

我怎样才能做到这一点?

P.S:我已经编辑了问题并添加了代码以供参考。

【问题讨论】:

  • 请向我们展示(在这个问题中)您实际询问的代码。您当前在此处的代码根本没有显示任何 ajax 调用。这个问题需要独立存在,而不是依赖于查看其他问题中的代码。
  • 另外,将成功和失败函数传递给返回承诺的东西实际上根本不是设计事物的方式。使用 promise 来处理成功和失败,而不是单独的回调。
  • @jfriend00 实际上我是从移动设备发布的,并且无法格式化代码,因为我看不到格式化工具栏,这就是为什么我提到了我之前提出的代码问题。不过,我已经编辑并添加了这个问题中的代码。
  • @jfriend00 我在上面发布的代码中使用了成功和错误回调,因为我无法在 then() 中获得第二次调用的响应。这就是我问这个问题的原因。如果我能够使用 then() 我不会使用回调。他们在那里是因为我似乎无法在 then() 中获得第二个承诺响应。
  • 请查看我发布的答案,因为它显示了使用嵌套承诺并将内部承诺的结果返回给生成的.then() 处理程序的正确方法。您不想按照其他答案中的建议创建额外的延迟,因为这是一种承诺反模式并会产生错误处理问题(请参阅我的答案中的解释)。

标签: javascript jquery ajax promise jquery-deferred


【解决方案1】:

要使.then() 在外部函数上工作,您必须从该函数中返回顶级承诺,如下所示:

self.getAjaxPromise = function (url, async, type, contentType, data, isSecureCall) {
    if (isSecureCall) {
        // return the outer promise from the function so .then() will work
        return getTokenPromiseFromServer().then(function (tokenData) { //This then runs fine
            // return this ajax call to chain it to the previous promise
            return $.ajax({
                beforeSend: function (request) {
                    request.setRequestHeader("authKey", tokenData.key);
                },
                url: url,
                async: async,
                type: type,
                contentType: contentType,
                data: JSON.stringify(data)
            });
        });
    } else { //Just one ajax call 
        return $.ajax({
            beforeSend: function (request) {
                request.setRequestHeader("authKey", "anonymous");
            },
            url: url,
            async: async,
            type: type,
            contentType: contentType,
            data: JSON.stringify(data)
        });
    }
};

然后,您可以像这样调用它,所有结果都将返回到 .then() 处理程序中,并且任何错误都会一直传播回来:

 xxx.getAjaxPromise(...).then(function(result) {
     // sucessfull result here
 }, function(err) {
     // error here
 });

创建额外的承诺或延迟,正如另一个答案所建议的那样,考虑promise anti-pattern,因为它完全没有必要并且经常会产生错误处理问题。相反,你可以只返回你已经拥有的承诺,当你有一个嵌套的承诺时,你可以从 .then() 处理程序中返回它,它会自动链接到第一个承诺,并控制最终的结果承诺。这将允许您的外部 .then() 处理程序工作并获得正确的结果。

【讨论】:

  • +1 教我一些东西。奇怪的是,在另一个问题的海报原始代码中(在他在这个问题中添加了稍微不同的代码之前),他返回了顶级承诺,而最终then 处理程序中的数据参数来自顶级承诺,而不是嵌套的。但是,我的 jsfiddle 测试表明它运行良好。
  • @Joel - 您的测试显示了什么工作正常,是 OP 的原始代码还是我建议的代码?
  • 两者都没有,我只是创建了一个人为的嵌套 promise 示例,并验证了所有内容都按预期顺序执行,并且每个回调的数据都正确流动。
【解决方案2】:

发生这种情况的原因是因为您正在返回来自return getTokenPromiseFromServer() 的承诺。在原始 ajax 调用完成之前,不会执行附加到该承诺的 .then 回调的 return 语句。因此,您的 .then 处理程序实际上是附加到来自 getTokenPromiseFromServer() 的承诺,而不是嵌套的 $.ajax 调用。

您需要对代码进行一些重构。 jQuery 提供了一种方法,在使用 $.when https://api.jquery.com/jquery.when/ 执行回调之前等待 promise 列表中的所有 promise 解决,根据您的需要,下面的选项可能更合适,但这是实现此目的的一种方法。

这是一个例子:

$.when(promise1, promise2, promise3).done(function (d1, d2, d3) {
    //d1 = data from promise1
    //d2 = data from promise2
    //d3 = data from promise3
});

当您执行代码以获取 Promise 时,您可以改为返回 Promise 列表并使用 $.when 等到所有 Promise 都得到解决。

如果您不关心来自getAjaxPromise 的外部getTokenPromiseFromServer(),则可以减少重构。在这种情况下,您可以手动创建一个延迟,从getAjaxPromise 返回,然后在getTokenPromiseFromServer() 的回调中,您可以像这样手动解决延迟。由于您要返回自己的延迟对象,因此 .then 处理程序将附加到该对象上,并且在您手动解决延迟对象之前不会执行(一旦嵌套的 $.ajax 被解决,您就可以执行此操作。使用这种方法,您可以嵌套任意数量的 ajax 调用,行为都是一样的。

if (isSecureCall) {
  var dfd = $.Deferred(); //create deferred
  getTokenPromiseFromServer().then(function(tokenData) {
    $.ajax({
      beforeSend: function(request) {
        request.setRequestHeader("authKey", tokenData.key);
      },
      url: url,
      async: async,
      type: type,
      contentType: contentType,
      success: successCallback, //Success callback runs fine, then() does not
      error: errorCallback, //Error callback runs fine, then() does not
      data: JSON.stringify(data)
    }).then(function( data, textStatus, jqXHR ) {
              dfd.resolve(data); //manually resolve the deferred which executes any callbacks attached to it
            });
  });
  return dfd; //return the deferred, which .then() will attach to
}

编辑 因为人们一直反对这个答案

正如@jfriend00 在他的回答中指出的那样,这被认为是一种承诺反模式,应该避免,因为它可能会在更复杂的场景中导致问题。感谢他纠正了我对 Promise 的理解。请参阅他的回答了解更多详情。

相反,可以通过简单地返回顶级承诺来链接承诺。并在返回的 Promise 上调用 .then,而不是手动创建一个 deferred 并解决它。

【讨论】:

  • 这种类型的答案被认为是promise anti-pattern,既不需要也不需要。相反,您应该只从主函数返回外部承诺,并从 .then() 处理程序中返回内部承诺。除了额外的、不必要的代码之外,这种反模式通常还会产生您的代码所具有的错误处理问题。如果内部 ajax 调用或外部 getTokePromiseFromServer() 承诺出现错误,这两个错误都将被默默吃掉而不返回来自函数。
【解决方案3】:

我不熟悉那个方法,但你为什么不在 jQuery Ajax 调用中使用简单的 jQuery Ajax 调用

$.ajax({//params)}.done(() => {   // other ajax  call.     
     $.ajax({  //params}).done((result) => {//target code
                                           }); 
})

【讨论】:

  • 只有这么简单。我有一个嵌套的 ajax 调用,并且需要在每次启动实际 ajax 之前调用一个服务。这些嵌套的 ajax 位于我从任何地方调用的单个函数中。我怎么能在我现有的场景中做到这一点。我不能到处都写这两个 ajax 调用。
猜你喜欢
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
相关资源
最近更新 更多