2016-05-12 5 views
0
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 then().Получить ответ второго вызова от обещания первого зова в

Как я могу это достичь?

P.S: Я отредактировал вопрос и добавил код для справки.

+0

Пожалуйста, покажите нам (в этом вопросе) код, о котором вы действительно спрашиваете. Код, который вы сейчас используете, не показывает никаких вызовов ajax вообще. Этот вопрос должен стоять на своем, не зависеть от взгляда на код в каком-то другом вопросе. – jfriend00

+0

Плюс, прохождение успешной и неудачной функции к чему-то, что возвращает обещание, на самом деле не способ дизайна вообще. Используйте обещание обрабатывать успех и неудачу, а не отдельные обратные вызовы. – jfriend00

+0

@ jfriend00 На самом деле я отправляю сообщения с мобильных устройств и не смог отформатировать код, потому что я не могу видеть панель инструментов форматирования, которая, как я уже упоминала, ранее задал вопрос для кода. Тем не менее, я редактировал и добавлял код в этот вопрос. – zeppelin

ответ

0

Причина это происходит потому, что вы возвращенная обещание return getTokenPromiseFromServer() , Оператор возврата из обратного вызова .then, прикрепленный к этому обещанию, не выполняется до завершения первоначального вызова ajax. Таким образом, ваш обработчик .then фактически привязан к обещанию от getTokenPromiseFromServer(), а не к вложенному вызову $.ajax.

Вам понадобится рефинансирование вашего кода. jQuery предоставляет метод ожидания всех обещаний в списке обещаний для решения перед выполнением обратного вызова с использованием $.whenhttps://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 
} 

EDITпоскольку люди продолжают downvoting этого ответа

Как @ jfriend00 указал в своем ответе, это считается обещанием антишаблон и его следует избегать, поскольку это может вызвать проблемы в более сложных ex сценарии. Спасибо ему за исправление моего понимания обещаний. Дополнительную информацию см. В его ответе.

Вместо этого обещания могут быть скованы простым возвратом обещания на высшем уровне. и вызывая .then по возвращенному обещанию, вместо того, чтобы вручную создавать отложенное и разрешать его.

+0

Спасибо человеку. Я получаю это сейчас. – zeppelin

+1

Этот тип ответа считается [обещают анти-шаблон] (https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns) и является нежелательным и ненужным. Вместо этого вы должны просто вернуть внешнее обещание из основной функции и вернуть внутреннее обещание из обработчика '.then()'. Помимо лишнего, ненужного кода этот анти-шаблон также обычно создает проблемы с обработкой ошибок, которые имеют ваш код. Если есть ошибка во внутреннем вызове ajax или на наружном обещании getTokePromiseFromServer(), обе эти ошибки будут беззвучно съедены и не возвращаются из функции. – jfriend00

+0

Избегайте [отложенного антипаттера] (http://stackoverflow.com/q/23803743/1048572)! – Bergi

0

Я не знаком с этим методом, но почему бы вам не использовать простой JQuery Ajax вызов внутри JQuery Ajax называют

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

Только если это было так просто. У меня есть вложенный вызов ajax и нужно вызывать услугу каждый раз до того, как будет запущен фактический аякс. И эти вложенные ajaxs находятся в одной функции, которую я вызываю от везде. Как я могу это сделать в моем существующем сценарии. Я не могу писать оба эти аякс-звонки везде. – zeppelin

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() работать и получить правильный результат.

+0

+1 для обучения чему-то. Как ни странно, в исходном коде плаката по другому вопросу (прежде чем он добавил немного другой код в этот вопрос), он возвращал обещание высшего уровня, а аргумент данных в последнем обработчике 'then' был от обещания высшего уровня, а не вложенный. Тем не менее, мои тесты jsfiddle показывают, что это работает отлично. – Joel

+0

@Joel - Ваши тесты показывают, что правильно работает, исходный код OP или мой предложенный код? – jfriend00

+0

, я просто создал надуманный пример вложенных обещаний и проверил, что все выполненное в ожидаемом порядке и данные для каждого обратного вызова протекают правильно. – Joel