如何让jQuery执行同步而不是异步的Ajax请求?

我有一个提供标准扩展点的JavaScript小部件。其中之一是beforecreate函数。它应该返回false以防止创建项目。

我使用jQuery在这个函数中添加了一个Ajax调用:

beforecreate: function (node, targetNode, type, to) {jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
function (result) {if (result.isOk == false)alert(result.message);});}

但是我想阻止我的小部件创建项目,所以我应该在母函数中返回false,而不是在回调中。有没有办法使用jQuery或任何其他浏览器内API执行同步AJAX请求?

807608 次浏览

jQuery留档开始:您将异步选项指定为虚假以获得同步Ajax请求。然后您的回调可以在您的母函数继续之前设置一些数据。

以下是如果按照建议更改您的代码会是什么样子:

beforecreate: function (node, targetNode, type, to) {jQuery.ajax({url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),success: function (result) {if (result.isOk == false) alert(result.message);},async: false});}

优秀的解决方案!当我尝试实现它时,我注意到如果我在成功子句中返回一个值,它会返回为未定义。我必须将其存储在一个变量中并返回该变量。这是我想出的方法:

function getWhatever() {// strUrl is whatever URL you need to callvar strUrl = "", strReturn = "";
jQuery.ajax({url: strUrl,success: function(html) {strReturn = html;},async:false});
return strReturn;}

您可以通过调用将jQuery的Ajax设置置于同步模式

jQuery.ajaxSetup({async:false});

然后使用jQuery.get( ... );执行Ajax调用

然后再把它打开一次

jQuery.ajaxSetup({async:true});

我想它的工作原理与@Adam的建议相同,但它可能对想要将其jQuery.get()jQuery.post()重新配置为更精细的jQuery.ajax()语法的人有所帮助。

function getURL(url){return $.ajax({type: "GET",url: url,cache: false,async: false}).responseText;}

//example usevar msg=getURL("message.php");alert(msg);

所有这些答案都忽略了一点,即使用async: false进行Ajax调用将导致浏览器挂起,直到Ajax请求完成。使用流控制库将解决这个问题,而无需挂起浏览器。这是一个Frame.js的例子:

beforecreate: function(node,targetNode,type,to) {
Frame(function(next)){
jQuery.get('http://example.com/catalog/create/', next);});
Frame(function(next, response)){
alert(response);next();});
Frame.init();}

这是一个例子:

$.ajax({url: "test.html",async: false}).done(function(data) {// Todo something..}).fail(function(xhr)  {// Todo something..});

我使用了Carcione给出的答案并将其修改为使用JSON。

 function getUrlJsonSync(url){
var jqxhr = $.ajax({type: "GET",url: url,dataType: 'json',cache: false,async: false});
// 'async' has to be 'false' for this to workvar response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};
return response;}
function testGetUrlJsonSync(){var reply = getUrlJsonSync("myurl");
if (reply.valid == 'OK'){console.dir(reply.data);}else{alert('not valid');}}

我添加了'JSON'数据类型并将响应文本更改为响应JSON

我还使用返回对象的状态正文属性检索了状态。请注意,这是Ajax响应的状态,而不是JSON是否有效。

后端必须以正确(格式良好)的JSON返回响应,否则返回的对象将是未定义的。

回答原始问题时需要考虑两个方面。一个是告诉Ajax同步执行(通过设置默认值async: false),另一个是通过调用函数的返回语句返回响应,而不是回调函数。

我也用POST尝试过,它奏效了。

我将GET更改为POST并添加data: postdata

function postUrlJsonSync(url, postdata){
var jqxhr = $.ajax({type: "POST",url: url,data: postdata,dataType: 'json',cache: false,async: false});
// 'async' has to be 'false' for this to workvar response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};
return response;}

请注意,上述代码仅在async虚假的情况下有效。如果您要设置async:true,则返回的对象jqxhr在AJAX调用返回时无效,只有在异步调用完成后才会返回,但设置反应变量为时已晚。

请记住,如果您正在进行跨域Ajax调用(通过使用JSONP)-您不能同步执行,async标志将被jQuery忽略。

$.ajax({url: "testserver.php",dataType: 'jsonp', // jsonpasync: false //IGNORED!!});

对于JSONP调用,您可以使用:

  1. Ajax调用到您自己的域-并在服务器端进行跨域调用
  2. 将代码更改为异步工作
  3. 使用“函数序列器”库,如Frame.js(此回答
  4. 阻止UI而不是阻止执行(这个回答)(我最喜欢的方式)

使用async: false,你会得到一个被阻止的浏览器。对于非阻塞同步解决方案,您可以使用以下内容:

ES6/ECMAScript2015

使用ES6,您可以使用生成器和共同图书馆

beforecreate: function (node, targetNode, type, to) {co(function*(){let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));//Just use the result here});}

ES7

对于ES7,你可以使用asyc wait:

beforecreate: function (node, targetNode, type, to) {(async function(){let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));//Just use the result here})();}

注意:由于此警告消息,您不应该使用async: false

从Gecko 30.0(Firefox 30.0/Thunderbird 30.0/SeaMonkey 2.27)开始,由于对用户体验的负面影响,主线程上的同步请求已被弃用。

Chrome甚至在控制台中警告说:

不建议使用主线程上的同步XMLHttpRequest,因为它会对最终用户的体验产生不利影响。有关更多帮助,请查看https://xhr.spec.whatwg.org/

如果你正在做这样的事情,这可能会破坏你的页面,因为它可能会在任何一天停止工作。

如果你想以一种仍然感觉像是同步但仍然不阻塞的方式来做,那么你应该使用async/wait,可能还有一些基于新拿过来 API等承诺的ajax

async function foo() {var res = await fetch(url)console.log(res.ok)var json = await res.json()console.log(json)}

编辑当页面被用户导航离开或关闭时,chrome正在处理在页面关闭中禁止同步XHR。这涉及beforeunload、unload、pagehide和visibilitychange。

如果这是您的用例,那么您可能希望查看navigator.send灯塔

页面也可以使用超文本传输协议标头或ifram的允许属性禁用同步请求

首先,我们应该了解何时使用$. ajax以及何时使用$. get/$. post

当我们需要对ajax请求进行低级控制时,例如请求标头设置、缓存设置、同步设置etc.then我们应该选择$. ajax。

$. get/$. post:当我们不需要对ajax请求进行低级控制时。只有简单的获取/发布数据到服务器。它是

$.ajax({url: url,data: data,success: success,dataType: dataType});

因此,我们不能在$. get/$. post中使用其他功能(同步、缓存等)。

因此,对于ajax请求的低级控制(同步、缓存等),我们应该选择$. ajax

 $.ajax({type: 'GET',url: url,data: data,success: success,dataType: dataType,async:false});

这是我用jQuery对ASYNC请求的简单实现。我希望这对任何人都有帮助。

var queueUrlsForRemove = ['http://dev-myurl.com/image/1','http://dev-myurl.com/image/2','http://dev-myurl.com/image/3',];
var queueImagesDelete = function(){
deleteImage( queueUrlsForRemove.splice(0,1), function(){if (queueUrlsForRemove.length > 0) {queueImagesDelete();}});
}
var deleteImage = function(url, callback) {$.ajax({url: url,method: 'DELETE'}).done(function(response){typeof(callback) == 'function' ? callback(response) : null;});}
queueImagesDelete();

因为XMLHttpReponse同步操作已被弃用,我想出了以下包装XMLHttpRequest的解决方案。这允许有序的AJAX查询,同时本质上仍然是异步的,这对于一次性使用的CSRF令牌非常有用。

它也是透明的,因此jQuery等库将无缝运行。

/* wrap XMLHttpRequest for synchronous operation */var XHRQueue = [];var _XMLHttpRequest = XMLHttpRequest;XMLHttpRequest = function(){var xhr   = new _XMLHttpRequest();var _send = xhr.send;
xhr.send = function(){/* queue the request, and if it's the first, process it */XHRQueue.push([this, arguments]);if (XHRQueue.length == 1)this.processQueue();};
xhr.processQueue = function(){var call = XHRQueue[0];var xhr  = call[0];var args = call[1];
/* you could also set a CSRF token header here */
/* send the request */_send.apply(xhr, args);};
xhr.addEventListener('load', function(e){/* you could also retrieve a CSRF token header here */
/* remove the completed request and if there is more, trigger the next */XHRQueue.shift();if (XHRQueue.length)this.processQueue();});
return xhr;};

由于最初的问题是关于jQuery.get的,这里值得一提的是(如这里所述)一个可以$.get()中使用async: false,但理想地避免它,因为异步XMLHTTPRequest已弃用(浏览器可能会发出警告):

$.get({url: url,// mandatorydata: data,success: success,dataType: dataType,async:false // to make it synchronous});