从第一个电话的承诺中获取第二个电话的响应

Get second call's response from first call's promise

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: 我已经编辑了问题并添加了代码以供参考。

我不熟悉那个方法,但你为什么不在 jQuery Ajax 调用

中使用一个简单的 jQuery Ajax 调用
$.ajax({//params)}.done(() => {   // other ajax  call.     
     $.ajax({  //params}).done((result) => {//target code
                                           }); 
})

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

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

这是一个例子:

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

当您执行代码以获得承诺时,您可以 return 承诺列表,并使用 $.when 等待所有承诺都得到解决。

如果您不关心 getAjaxPromise 外部的 getTokenPromiseFromServer(),您可以通过较少的重构来逃脱。在这种情况下,您可以手动创建一个来自 getAjaxPromise 的延迟 return,然后在 getTokenPromiseFromServer() 的回调中,您可以像这样手动解决延迟。由于您正在 returning 您自己的延迟对象,因此 .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 的理解。有关更多详细信息,请参阅他的回答。

相反,可以通过简单地 returning 顶级承诺来链接承诺。并在 returned 承诺上调用 .then,而不是手动创建延迟并解决它。

要使 .then() 在外部函数上工作,您必须 return 从该函数内部像这样的顶级承诺:

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)
        });
    }
};

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

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

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