如何在没有 async = false 的情况下执行 jQuery 阻塞 AJAX 调用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11062803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I do a jQuery blocking AJAX call without async = false?
提问by ChrisV
I have a page which does AJAX validation of an email before continuing on to the next page, using the HTML5 setCustomValidity() method [using the webshims library for older browsers].
我有一个页面在继续到下一页之前对电子邮件进行 AJAX 验证,使用 HTML5 setCustomValidity() 方法[使用旧浏览器的 webshims 库]。
For this to work, I set the async option to false in the $.ajax() call to make it synchronous, blocking the page pending the AJAX response, as otherwise the form submits before the ajax call returns, rendering the validation ineffectual.
为此,我在 $.ajax() 调用中将 async 选项设置为 false 以使其同步,阻止页面等待 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>
I see that the async option is to be deprecated as of jQuery 1.8.
我看到 async 选项从 jQuery 1.8 开始被弃用。
How can I achieve this blocking action without the async option?
如何在没有异步选项的情况下实现此阻止操作?
回答by Mike
http://bugs.jquery.com/ticket/11013#comment:40
http://bugs.jquery.com/ticket/11013#comment:40
The use of the Deferred/Promise functionality in synchronous ajax requests has been deprecated in 1.8. The $.ajax method with async: false is supported but you must use a callback parameter rather than a Promise method such as
.then
or.done
.
在 1.8 中不推荐在同步 ajax 请求中使用延迟/承诺功能。支持带有 async: false 的 $.ajax 方法,但您必须使用回调参数而不是 Promise 方法,例如
.then
or.done
。
So, if you are using the success/complete/error handlers, you can still use async:false
. More info at the jquery ticket above.
因此,如果您使用的是成功/完成/错误处理程序,您仍然可以使用async:false
. 更多信息请见上面的 jquery 票证。
回答by sonjz
As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the complete/success/error callbacks.
http://api.jquery.com/jQuery.ajax/(async section)
从 jQuery 1.8 开始,不推荐使用带有 jqXHR ($.Deferred) 的 async: false ;您必须使用完整/成功/错误回调。
I found this a bit annoying... developers should be given the choiceto make a blocking call with async: false
if its something the platform allows - why restrict it? I'd just set a timeout to minimize the impact of a hang.
我发现这有点烦人......如果平台允许,开发人员应该选择进行阻塞调用async: false
- 为什么要限制它?我只是设置了一个超时来最小化挂起的影响。
Nonetheless, I'm using a queue now in 1.8, which is non-blocking, and works quite nicely. Sebastien Roch created a easy to use utility that allows you to queue up functions and run/pause them. https://github.com/mjward/Jquery-Async-queue
尽管如此,我现在在 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();
In the first 2 functions I pass the queue
object into the calls, here's what the calls would look like:
在前 2 个函数中,我将queue
对象传递给调用,这是调用的样子:
function ajaxCall1(queue) {
queue.pause();
$.ajax({
// your parameters ....
complete: function() {
// your completing steps
queue.run();
}
});
}
// similar for ajaxCall2
Notice the queue.pause();
at the beginning of each function, and queue.run()
to continue queue execution at the end of your complete
statement.
注意queue.pause();
每个函数开头的 ,并queue.run()
在complete
语句结束时继续队列执行。
回答by Jonathan Nicol
I assume you will be doing full form validation on submit anyway, so perhaps it's no problem if the as-you-type email validation is interrupted, and precedence given to the form submission.
我假设您无论如何都会在提交时进行完整的表单验证,所以如果您输入的电子邮件验证被中断,并且优先提交表单,也许这没有问题。
I think what I'd do is abort the 'validateEmailRegistered' AJAX request when the user submits the form. Then, perform full server-side form validation as usual - including email validation.
我想我要做的是在用户提交表单时中止“validateEmailRegistered”AJAX 请求。然后,像往常一样执行完整的服务器端表单验证 - 包括电子邮件验证。
My understanding of as-you-type validation is that it's a nicety, not a substitute for validating the form when it is submitted. So it doesn't make sense to me for it to block the form submission.
我对 as-you-type 验证的理解是,它是一种很好的方式,不能替代在提交表单时对其进行验证。所以阻止表单提交对我来说没有意义。
回答by Savageman
I think you need to change a bit how you it works. Don't try to achieve blocking, but embrace non-blocking.
我认为您需要稍微改变一下它的工作方式。不要试图实现阻塞,而是拥抱非阻塞。
I would do like this: - Keep the validation on email; make it Asynchronous. When it's valid, set a flag somewhere in a variable to know it's ok. - Add a callback on the form.submit() to check whether the email is ok (with the variable) and prevent the submission if it's not.
我会这样做: - 在电子邮件中保留验证;使其异步。当它有效时,在变量中的某处设置一个标志以知道它没问题。- 在 form.submit() 上添加回调以检查电子邮件是否正常(使用变量),如果不正常则阻止提交。
This way you can keep asynchronous call without freeze the web browser UI.
通过这种方式,您可以保持异步调用而不会冻结 Web 浏览器 UI。
-- [edit] --
- [编辑] -
This is some quick code I just wrote for the example based on what you already have.
这是我刚刚根据您已有的内容为示例编写的一些快速代码。
For your information, a programming notion called "promises" (futures and deferred are other terms for it) has been invented to solve exactly the problem you have.
为了您的信息,已经发明了一种称为“promises”(期货和延迟是它的其他术语)的编程概念来准确地解决您遇到的问题。
Here's an article on what it is and how to use them in JavaScript (using dojo or jQuery): http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx
这是一篇关于它是什么以及如何在 JavaScript 中使用它们的文章(使用 dojo 或 jQuery):http: //blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript -with-promises.aspx
<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>
回答by Ryley
If you are really set on not letting them submit the form until you have checked the email validity, start out your submit button with the disabled
attribute, then have the callback set $('form button').removeAttr('disabled');
如果您真的决定在检查电子邮件有效性之前不让他们提交表单,请使用disabled
属性开始提交按钮,然后设置回调$('form button').removeAttr('disabled');
That being said, I'm with the other people - just let them submit the form! Usually people get it right and you pass them right on through with no errors...
话虽如此,我和其他人在一起 - 让他们提交表格!通常人们做对了,你把它们正确地传递过去,没有错误......
回答by Ken Johnson
You can do it asynchronously.
您可以异步执行此操作。
Create a global variable, I call it ajax_done_and_successful_flag, that you initialize to false at the beginning of the program. You will set this to true or false at various places in your Ajax functions such as your Ajax success function or your Ajax error function.
创建一个全局变量,我称之为 ajax_done_and_successful_flag,在程序开始时将其初始化为 false。您将在 Ajax 函数(例如 Ajax 成功函数或 Ajax 错误函数)的不同位置将其设置为 true 或 false。
Then you need to add a submit handler at the bottom of your validate function.
然后您需要在验证函数的底部添加一个提交处理程序。
submitHandler: function(form) {
if (ajax_done_and_successful_flag === true) {
form.submit()
}
}
The problem is the code is not executing in a linear way.
Put a bunch of Firebug's console.log statements in your code.
Observe the sequence of execution. You will see that your
Ajax response will come back last, or whenever it feels like it.
That's why you need the submitHandler AND the global flag
to force the validate function to wait for correct Ajax
results before the form is submitted.
问题是代码没有以线性方式执行。
在您的代码中放入一堆 Firebug 的 console.log 语句。
观察执行顺序。您将看到您的
Ajax 响应将最后返回,或者在需要时返回。
这就是为什么您需要 submitHandler 和全局标志
来强制验证函数
在提交表单之前等待正确的 Ajax结果。
Any output to the screen from the Ajax response,
needs to be done in the
Ajax functions, such as the success function and the
error function.
You need to write to the same location
as the validate function's success/error functions.
This way the Ajax error messages blend in with the validate function's
error function.
This concept may seem a bit tricky.
The idea to keep in
mind is that the success and error functions in the validate function
are writing to the same location as the success and error
functions in the Ajax call, and that is okay, that is how
it should be.
The location of my error messages is right next to where the
user types the input. This creates a nice user experience
that I think you are asking for.
从 Ajax 响应到屏幕的任何输出都需要在 Ajax 函数中完成,例如成功函数和错误函数。
您需要写入与验证函数的成功/错误函数相同的位置。
通过这种方式,Ajax 错误消息与验证函数的错误函数混合在一起。
这个概念可能看起来有点棘手。
要记住的想法是验证函数中的成功和错误函数写入与 Ajax 调用中的成功和错误函数相同的位置,这没问题,应该是这样。
我的错误消息的位置就在用户键入输入的位置旁边。这创造了我认为您所要求的良好用户体验。
Here is my code sample. I simplified it.
这是我的代码示例。我简化了它。
I am running jQuery-1.7.1
and jQuery validation plug-in 1.6
I am using Firefox 14.0.1 and I also tried
it on Chrome 21.0 successfully.
我正在运行 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
}
The reg_entry_error is the place right beside the text input. Here is a simplified code sample of the form.
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>
I hope this answers your question.
我希望这回答了你的问题。