Подтвердить что ты не робот

Как сделать jQuery, блокирующий вызов AJAX без async = false?

У меня есть страница, которая проверяет правильность AJAX для электронной почты, прежде чем перейти к следующей странице, используя метод HTML5 setCustomValidity() [используя библиотеку webshims для более старых браузеров].

Для этого я установил для параметра async значение false в вызове $.ajax(), чтобы сделать его синхронным, заблокировав страницу до ответа AJAX, так как в противном случае форма отправляется перед возвратом вызова ajax, оказывая валидацию неэффективен.

<script>
  function validateEmailRegistered(input) {
    if (input.setCustomValidity === undefined) return;
    var err = 'Email address not found';
    $.ajax({
      url: 'email-is-registered.php', 
      data: { email: input.value }, 
      async: false, 
      success: function(data) {
        var ok = data=='true';
        input.setCustomValidity(ok ? '' : err)
      }
    });
  }
</script>

<form method="get" action="nextpage.php">
  <input name="email" id="email" type="email" required
    onChange="validateEmailRegistered(this)">
  <button type="submit">go</button>
<form>

Я вижу, что параметр async должен быть устаревшим как jQuery 1.8.

Как я могу достичь этого действия блокировки без опции async?

4b9b3361

Ответ 1

http://bugs.jquery.com/ticket/11013#comment:40

Использование функциональности "Отсрочка/обещание" в синхронных запросах ajax устарело в 1.8. Метод $.ajax с async: false поддерживается, но вы должны использовать параметр обратного вызова, а не метод Promise, например .then или .done.

Итак, если вы используете обработчики success/complete/errors, вы все равно можете использовать async:false. Дополнительная информация о билете jquery выше.

Ответ 2

Как и в jQuery 1.8, использование async: false с jqXHR ($.Deferred) является осуждается; вы должны использовать полные/успешные/обратные вызовы.

http://api.jquery.com/jQuery.ajax/ (раздел async)

Я нашел это немного раздражающим... разработчикам должен быть предоставлен выбор сделать блокирующий вызов с помощью async: false, если это то, что позволяет платформа - зачем его ограничивать? Я просто установил тайм-аут, чтобы минимизировать влияние зависания.

Тем не менее, я использую очередь в 1.8, которая не блокирует и работает довольно хорошо. Sebastien Roch создал простую в использовании утилиту, которая позволяет вам ставить в очередь функции и запускать/приостанавливать их. https://github.com/mjward/Jquery-Async-queue

    queue = new $.AsyncQueue();
    queue.add(function (queue) { ajaxCall1(queue); });
    queue.add(function (queue) { ajaxCall2(queue); });
    queue.add(function() { ajaxCall3() });
    queue.run();

В первых двух функциях я передаю объект queue в вызовы, вот как выглядят вызовы:

function ajaxCall1(queue) {
    queue.pause();
    $.ajax({
       // your parameters ....
       complete: function() {
         // your completing steps
         queue.run();
       }
    });
}

// similar for ajaxCall2

Обратите внимание на queue.pause(); в начале каждой функции и queue.run(), чтобы продолжить выполнение очереди в конце вашего оператора complete.

Ответ 3

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

Я думаю, что я бы сделал, это прервать запрос "validateEmailRegistered" AJAX, когда пользователь отправляет форму. Затем выполните полную проверку на стороне сервера как обычно - включая проверку электронной почты.

Мое понимание валидации типа "как есть" заключается в том, что это тонкость, а не замена для проверки формы при ее отправке. Поэтому для меня не имеет смысла блокировать отправку формы.

Ответ 4

Думаю, вам нужно немного изменить, как вы это делаете. Не пытайтесь добиться блокировки, но не блокируйте.

Я бы сделал следующее: - Держать подтверждение по электронной почте; сделайте его асинхронным. Когда он действителен, установите флаг где-нибудь в переменной, чтобы знать его в порядке. - Добавьте обратный вызов в form.submit(), чтобы проверить, нормально ли письмо (с переменной), и предотвратить отправку, если это не так.

Таким образом вы можете сохранить асинхронный вызов без зависания интерфейса веб-браузера.

- [edit] -

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

Для вашей информации было разработано понятие программирования, называемое "promises" (фьючерсы и отложенные для него другие термины), чтобы решить именно ту проблему, которая у вас есть.

Вот статья о том, что это такое и как использовать их в JavaScript (используя dojo или jQuery): http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx p >

<script>
  function validateEmailRegistered(input) {
    if (input.setCustomValidity === undefined) return;
    var err = 'Email address not found';
    $.ajax({
      url: 'email-is-registered.php', 
      data: { email: input.value }, 
      success: function(data) {
        var ok = data=='true';
        input.setCustomValidity(ok ? '' : err);
        // If the form was already submited, re-launch the check
        if (form_submitted) {
            input.form.submit();
        }
      }
    });
  }

  var form_submitted = false;

  function submitForm(form) {
    // Save the user clicked on "submit"
    form_submitted = true;
    return checkForm(form);
  }

  function checkForm(form, doSubmit) {
    if (doSubmit) {
        form_submitted = true;
    }
    // If the email is not valid (it can be delayed due to asynchronous call)
    if (!form.email.is_valid) {
        return false;
    }
    return true;
  }
</script>

<form method="get" action="nextpage.php" onsumbit="return submitForm(this);">
  <input name="email" id="email" type="email" required
    onChange="validateEmailRegistered(this)">
  <button type="submit">go</button>
<form>

Ответ 5

Если вы действительно не разрешаете им отправлять форму до тех пор, пока вы не проверите достоверность электронной почты, запустите свою кнопку отправки с помощью атрибута disabled, затем установите обратный вызов $('form button').removeAttr('disabled');

Это, как говорится, я с другими людьми - просто дайте им представить форму! Обычно люди понимают это правильно, и вы передаете их прямо без ошибок...

Ответ 6

Вы можете сделать это асинхронно.

Создайте глобальную переменную, я называю ее ajax_done_and_successful_flag, что вы инициализируете значение false в начале программа. Вы установите для этого значение true или false на разных места в ваших функциях Ajax, таких как ваш успех Ajax функции или вашей функции ошибки Ajax.

Затем вам нужно добавить обработчик отправки в нижней части вашего validate function.

submitHandler: function(form) {
   if (ajax_done_and_successful_flag === true) {
     form.submit()
   }
}  

Проблема заключается в том, что код не выполняется линейным способом.
Поместите кучу отчетов Firebug console.log в свой код.
Соблюдайте последовательность выполнения. Вы увидите, что ваш Ответ Ajax вернется последним, или когда это будет похоже.
Вот почему вам нужен submitHandler И глобальный флаг
заставить функцию validate ожидать правильного Ajax
результаты перед отправкой формы.

Любой вывод на экран из ответа Ajax, должны быть выполнены в Функции Ajax, такие как функция успеха и функция ошибки.
Вам нужно написать в том же месте как функции проверки/ошибки функции проверки.
Таким образом, сообщения об ошибках Ajax смешиваются с функцией проверки подлинности функция ошибки.
Эта концепция может показаться немного сложной.
Идея сохранить ум заключается в том, что функции успеха и ошибки в функции проверки достоверности записываются в том же месте, что и успех и ошибка функции в вызове Ajax, и это нормально, вот как это должно быть. Расположение сообщений об ошибках находится рядом с пользователь вводит ввод. Это создает приятный пользовательский интерфейс что, я думаю, вы просите.

Вот мой пример кода. Я упростил его.

Я запускаю jQuery-1.7.1
и подключаемый модуль проверки jQuery 1.6
Я использую Firefox 14.0.1, и я также попробовал это на Chrome 21.0 успешно.

 var ajax_done_and_successful_flag = false;

 // Add methods
  ...

 $.validator.addMethod("USERNAME_NOT_DUPLICATE", function (value, element) {
   return this.optional(element) || validate_username_not_duplicate( );
  },
  "Duplicate user name.");

// validate
$(document).ready(function ( ) {
   $('#register_entry_form form').validate({
      rules: {
         username: {
         required: true,
         minlength: 2,
         maxlength: 20,
         USERNAME_PATTERN: true,
         USERNAME_NOT_DUPLICATE: true
        },    
    ...
    errorPlacement: function (error, element) { 
       element.closest("div").find(".reg_entry_error").html(error);
    },
    success: function(label) {
       label.text('Success!');
    } ,

    submitHandler: function(form) {   
       if (ajax_done_and_successful_flag === true ) {    
          form.submit();
       }
    }
  });
});

/* validation functions*/

function validate_username_not_duplicate() {

   var username_value = $('#username').val(); // whatever is typed in

   $.ajax({
      url: "check_duplicate_username.php",
      type: "POST",
      data: { username: username_value },
      dataType: "text",
      cache: false,
      //async: false,
      timeout: 5000,
      error: function (jqXHR, errorType, errorMessage) {
         ajax_done_and_successful_flag = false;

        if ( errorType === "timeout" ) {
           $('#username').closest("div").find(".reg_entry_error").html("Server timeout, try again later" );
        } else if ...

      },

      success:  function (retString, textStatus,jqXRH) {

        if ( retString === "yes") { // duplicate name 
           // output message next to input field        
           $('#username').closest("div").find(".reg_entry_error").html("Name already taken.");
           ajax_done_and_successful_flag = false;
        } else if ( retString === "no") { // name is okay
           // output message next to input field
           $('#username').closest("div").find(".reg_entry_error").html("success!");
           ajax_done_and_successful_flag = true;

        } else {
           console.log("in validate_username_duplicate func, success function, string returned was not yes or no." );
           $('#username').closest("div").find(".reg_entry_error").html("There are server problems. Try again later.");
           ajax_done_and_successful_flag = false;
       }
     } // end success function

   }); // end ajax call


  return true; // automatically return true, the true/false is handled in
              // the server side program and then the  submit handler

}

Reg_entry_error - это место рядом с текстовым вводом. Вот упрощенный пример кода формы.

  <label class="reg_entry_label" for="username">Username</label>
  <input class="reg_entry_input" type="text" name="username" id="username" value="" />
  <span class="reg_entry_error" id="usernameError" ></span>  

Надеюсь, это ответит на ваш вопрос.