2016-01-07 2 views
1

Я хочу отправить запрос Ajax и выполнить некоторые несвязанные действия во время поступления данных. После окончания действия мне нравится ждать окончания Ajax и выполнять другие действия.Смешение синхронных функций и асинхронных отложенных объектов jQuery

Для того, чтобы быть конкретными позволяет видеть, чтобы раздели например:

$.ajax({url: "/reqA"}) 
    .done(updateA) 
    .done($.ajax("/reqB").done(updateB)) 
    .done(updateFinal) 

updateFinal должен быть выполнен после завершения синхронного и асинхронного updateA/reqB и следующего синхронной updateB.

Выше кода неверен, потому что все последующие .done() действует по договору с /regA, а состояние гонки происходит между updateB и updateFinal.

я могу исправить код с .then:

$.ajax({url: "/reqA"}) 
    .done(updateA) 
    .then($.ajax("/reqB").done(updateB)) 
    .done(updateFinal) 

Но затем я хочу, чтобы запустить updateA после отправки запроса /reqB (потому что JS двигатель однопоточный и updateA исполнения заблокировало асинхронный процесс /reqB !!).

следующий код не работает:

$.ajax({url: "/reqA"}) 
    .then($.ajax("/reqB").done(updateB)) 
    .done(updateA) 
    .done(updateFinal) 

потому что updateA исполнение будет отложено до updateB исполнения !!

Я думаю, что проблема может быть решена с помощью функции $.when, но updateA не является обещанием, и я не вижу порядка выполнения гарантии в официальном $.when документах. Это может выглядеть следующим образом:

$.ajax({url: "/reqA"}) 
    .then(
     $.when(
       $.ajax("/reqB").done(updateB), 
       fakeResolvedPromiseWrapperAroundSyncFunc(updateA) 
     ) 
    ).done(updateFinal) 

Есть ли стандартный fakeResolvedPromiseWrapperAroundSyncFunc решение в библиотеке JQuery?

Любой другой путь для запуска синхронного кода после запуска асинхронного и последующего присоединения к результату асинхронного вызова?

+0

Не знаю, что такое 'updateA' и' updateB' ... используйте результат соответствующего '$ .ajax' для выполнения своей функции? Ваши более поздние фрагменты кода предполагают, что они не –

ответ

4

В ваших обработчиках .done() и .then() вам необходимо передать функцию «ССЫЛКИ», а не просто вызвать функции в parens, чтобы иметь возможность контролировать время выполнения.

В цепочке обещаний вы можете передавать либо синхронную функцию, либо асинхронную функцию как обработчик .then(). Если вы передаете асинхронную функцию, ей просто нужно вернуть обещание, и это обещание будет вставлено в цепочку обещаний в этот момент. Синхронная функция будет вызвана только тогда, когда она начнет свою очередь, а затем следующий шаг в цепочке пойдет сразу после нее (так как это синхронно).

Например, изменить:

$.ajax({url: "/reqA"}) 
    .done(updateA) 
    .done($.ajax("/reqB").done(updateB)) 
    .done(updateFinal) 

к этому:

$.ajax({url: "/reqA"}) 
    .then(updateA) 
    .then(function() { 
     return $.ajax("/reqB").then(updateB) 
    }).then(updateFinal); 

Или это может быть записано как:

$.ajax({url: "/reqA"}) 
    .then(updateA) 
    .then(function() { 
     return $.ajax("/reqB"); 
    }).then(updateB) 
    .then(updateFinal); 

Это будет выполнять функцию Ajax и когда вызов Ajax завершается, он выполнит updateA(). После завершения синхронного updateA() он вызовет анонимную функцию, которая затем выполнит вызов ajax/reqB. Когда этот вызов ajax завершится, он выполнит updateB(). Когда будет выполнено updateB(), то будет вызван updateFinal().

И изменить это:

$.ajax({url: "/reqA"}) 
    .then($.ajax("/reqB").done(updateB)) 
    .done(updateA) 
    .done(updateFinal) 

к этому:

$.ajax({url: "/reqA"}) 
    .then(function() { 
     return $.ajax("/reqB").then(updateB); 
    }).then(updateA) 
    .then(updateFinal) 

Когда вы непосредственно выполнять функцию внутри скобок, как вы делали, это называется НЕМЕДЛЕННО и обратный результат от выполнения функция - это то, что передается как обработчик .then(). Когда вы передаете ссылку на функцию, инфраструктура .then() может затем вызвать эту функцию через некоторое время.


Ваше использование $.when() также может работать. Он используется, когда вы хотите выполнять несколько элементов параллельно и хотите знать, когда все будет сделано. Рекомендации, приведенные выше, выполняют сериализованное исполнение (одно за другим).


Что касается смешивания синхронного и асинхронного кода, который может работать отлично. Первая операция в последовательности должна создать обещание, с которым вы можете связать обработчик .then(). После этого, обратный вызов для любого заданного .then() обработчика может выполнить одно из следующих действий:

  1. Это может быть синхронным и вернуть регулярное значение. Это значение становится разрешенным значением цепочки обещаний, а затем последующие обработчики .then() вызывают передачу этого значения им.

  2. Он может быть синхронным и не возвращать значение. Цепочка обещаний имеет значение undefined в этой точке и будет вызываться следующий обработчик .then() в цепочке.

  3. Он может быть синхронным и выдавать исключение. Исключением становится отклоненное значение текущего обещания и вызываемые обработчики отклонения .then(), а не вызывающие обработчики.

  4. Он может быть асинхронным и возвращать обещание. Это новое обещание вставляется в цепочку, а последующие .then() обработчики не вызываются до тех пор, пока это новое обещание не будет выполнено. Независимо от того, будут ли вызваны последующие разрешения или обработчики отклонения, будет зависеть от того, будет ли это новое обещание разрешаться или отклоняться.

  5. Он может быть асинхронным и не возвращать ничего или возвращать правильное (безоговорочное) значение. В этом случае запускается новая асинхронная операция, но она не влияет на текущую цепочку обещаний, потому что никаких обещаний, связанных с новой асинхронной операцией, не было возвращено. Эта новая асинхронная операция запускается сама по себе, и когда она заканчивается, она не влияет на текущую цепочку обещаний. Поскольку никаких обещаний не возвращается из .then() обработчика, текущее обещание продолжается, как будто это был синхронный обработчик, как описано

+0

Добавлены примечания о смешивании синхронного и асинхронного кода. – jfriend00

1

У меня немного трудное время выяснить, что именно вам нужно, но я думаю, что это что-то вроде этого:

// start ajax A 
var ajax_A = $.ajax({url: "/reqA"}); 

// wait for ajax A to complete before starting ajax B 
var ajax_B = ajax_A.then(function() { 
    return $.ajax({url: "/reqB"}); 
}); 

// perform the updates when the respective ajax completes 
var done_A = ajax_A.then(updateA); 
var done_B = ajax_B.then(updateB); 

// once ajax/update done for both A and B, run updateFinal 
$.when(done_A, done_B).then(updateFinal); 

Я считаю, что выше, также может быть записана следующим образом: - не зная специфику функции updateA Я только предполагаю,

$.ajax({url: "/reqA"}) 
.then(function(resultA) { 
    return $.when(updateA(resultA), $.ajax({url: "/reqB"}).then(updateB)) 
}) 
.then(updateFinal); 

Я использовал .then не .done - Я не очень знакомы с JQuery уникальной и не соответствует (по отношению к Promise/A + спецификации) интерпретация Promises - вы можете, или даже нужно использовать . Вместо этого в некоторых местах в приведенном выше коде

Я только что прочитал документацию с отложенной jquery, и кажется, что .done следует использовать вместо .then в приведенном выше кодексе - но я не могу быть уверен, я думаю вы можете знать лучше, поскольку вы, похоже, знакомы с jQuery отложенным


Как для fakeResolvedPromiseWrapperAroundSyncFunc - с помощью собственных обещаний (если таковые имеются), которые были бы просто

Promise.resolve(syncFunction()); 

да, () должен быть там, потому что вы хотите, чтобы решить результат вызова синхронизации функция

не уверен, JQuery имеет эквивалент ... но это может работать

var resolveIt(value) { 
    var deferred = $.deferred; 
    deferred.resolve(value); 
    return deferred.promise(); 
} 

resolveIt(syncFunction()); 

Обратите внимание, что, по крайней мере, в Promise/A + spec, тогда цепочки и Promise.all (похожие на $ .when) вам очень редко нужен такой kludge