JQuery AJAX: сбор нескольких асинхронных результатов

Я выполняю проверку данных формы, так что, когда кто-то нажимает кнопку отправки, он сначала проверяет содержимое формы. Ряд полей (может быть равен нулю, может быть более одного, в зависимости от страницы) имеют такие вещи, как уникальные коды, которые требуют проверки с сервером в первую очередь. Я запускаю асинхронный запрос на сервер, который просто отвечает "ok" или "taken" для каждого поля. Если какое-либо из полей имеет ошибки, страница не отправляется.

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

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

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

Разъяснение

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

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

$("form").submit(function () {
 return validate($(this));
});

Если метод validate() возвращает false, форма не отправляется. validate() hilights любые поля, которые не принимаются. Для нормальных полей validate() выглядит примерно так (значительно упрощенная версия без обратной связи):

function validate(form) {
 resetWarnings(form);
 var ok = true;
 // required fields
 form.find("input.required").each(function () {
 var field = $(this);
 if (field.val() === "") {
 ok = false;
 }
 return this; // meaningless in this case but a good habit to keep
 });
 // fields that matches a pattern
 form.find("input.pattern").each(function () {
 var field = $(this);
 var pattern = field.data("pattern");
 if (!field.val().match(pattern)) {
 ok = false;
 }
 return this;
 });
 // various other rules for other sorts of field
 ...
 return ok;
}

Для полей AJAX это выглядит следующим образом:

form.find("input.lookup").each(function () {
 var field = $(this);
 var url = field.data("lookup");
 $.ajax({
 url: url,
 data: { code: field.val() },
 success: function (result) {
 if (result === "taken") {
 ok = false;
 }
 }
 }
 });

Но, конечно, validate() уже закончил до вызова метода success. Поэтому, если я могу заставить его подождать, пока аякс не будет завершен (либо успех, либо ошибка), прежде чем вернуться, я могу получить правильный результат и остановить отправку формы. И если я сделал ajax синхронным, тогда весь метод остановится, пока не будет сделано, что неверно.

Дальнейшая мысль

Учитывая Javascript-модель потоковой передачи (которая вообще ничего не говорит), то, что я прошу технически невозможно?

3 ответа

С помощью jQuery 1.5+ лучший способ сбора данных результата из нескольких асинхронных запросов - использовать объекты с отсрочкой, которые представляют эти запросы со своими состояниями, и функцию-оболочку $.when(...). then (allRequestsCompleteCallback(), someRequestFailedCallback())

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

Пример JavaScript/jQuery:

function ajax1() { return $.ajax({ url: 'server1.php' }) }
function ajax2() { return $.ajax({ url: 'server2.php' }) }
$.when( ajax1(), ajax2() ).then(
 function() {
 // ajax1 AND ajax2 succeeded
 },
 function() {
 // ajax1 OR ajax2 succeeded
 }
);

Проверьте дополнительные документы и примеры здесь:


Если вы правильно поняли, вы хотите проверить, что значения (1.. *), введенные в форме, уникальны, как только пользователь нажимает кнопку отправки перед выполнением сообщения в форме. Если это так, я бы создал массив полей и значений JSON и отправлю его все сразу - так что вы только ожидаете ответа. Это должно быть довольно просто, используя функцию jQuery "each" и используя jQuery ajax.

Затем вы можете проверить единственный результат перед отправкой формы.

Это, вероятно, само собой разумеется, но обязательно повторите один и тот же валидационный сервер, как только вы разместите его, чтобы избежать условий гонки с другими пользователями.

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


Как насчет использования .ajaxStop:

$(document).ajaxStop(function() { 
 $(this).unbind("ajaxStop");
 // run validate method here
 }); 
 //run asynchronous validations here

Обратите внимание, что unbind необходимо, если сама validate() включает вызов AJAX.

licensed under cc by-sa 3.0 with attribution.