从第一个电话的承诺中获得第二个电话的回复

时间:2016-05-12 21:20:19

标签: javascript jquery ajax promise jquery-deferred

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中的ajax的响应' s然后()。

我如何实现这一目标?

P.S:我编辑了这个问题,并添加了代码供参考。

3 个答案:

答案 0 :(得分: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 :(得分:0)

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

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

答案 2 :(得分:0)

发生这种情况的原因是因为您从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
});

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

如果您不关心getTokenPromiseFromServer()外部的getAjaxPromise,那么您可以减少重构。在这种情况下,您可以手动创建延迟,从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上调用.then,而不是手动创建延迟并解析它。