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


1207

我有一个提供标准扩展点的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请求?


30
解决该问题的正确方法是重写小部件的扩展点使用承诺。这样可以轻松地将您设置为异步操作(例如ajax请求)beforecreate
科斯2013年

3
我建议使用Sajak函数。我们有字母T吗?是的,凡娜,给我3吨。
Cody O'Dell,2016年

2
@Kos在现场。这里不需要同步XHR
Michael Westcott

1
如果人们在启动javascript时要求我提供1条建议,我会说:拥抱javascript的异步特性,请不要尝试ty对抗。
伊曼纽尔(Emmanuel)延迟

3
这个问题就像问“我如何以纯文本格式存储用户密码?” 当然有答案,但是不要这样做。
Vectorjohn

Answers:


1165

jQuery文档中:您将异步选项指定为false,以获取同步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
    });
}

97
确实,不可能将get(),post(),load()用于同步调用。仅ajax()具有“ async”参数,可以将其设置为“ false”。
SLA80'5

39
@ SLA80不。由于jQuery的1.1:stackoverflow.com/questions/6849686/...
StuperUser

16
@qualidafial我的评论针对的是SLA80的错误评论;可以使用get(),post(),load()进行同步调用。
StuperUser 2012年

9
jQuery> = 1.8不再支持async false。请参阅api.jquery.com/jQuery.ajax

22
async: falsejQuery> = 1.8仍支持@ken 。不推荐使用async: false与jqXHR($.Deferred)一起使用的功能。换句话说,必须使用较新的成功/错误/完成回调选项,而不是传统方法jqXHR.done()
本·约翰逊

255

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

jQuery.ajaxSetup({async:false});

然后使用以下命令执行Ajax调用 jQuery.get( ... );

然后再打开一次

jQuery.ajaxSetup({async:true});

我想它的工作原理与@Adam所建议的一样,但对于希望重新配置其语法jQuery.get()jQuery.post()更复杂的jQuery.ajax()语法的人可能会有所帮助。


56
这是一个非常糟糕的主意,为什么要在全球范围内设置呢?然后被迫取消设置吗?
Juan Mendes

11
至少,这是最好的坏主意。而不是说:“没有办法$.ajax()”。;)
Rzassar

136

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

function getWhatever() {
  // strUrl is whatever URL you need to call
  var strUrl = "", strReturn = "";

  jQuery.ajax({
    url: strUrl,
    success: function(html) {
      strReturn = html;
    },
    async:false
  });

  return strReturn;
}

16
这是因为您是从回调而不是从中返回值getWhatever。因此,你回什么,即undefined从您getWhatever
Lightness Races in Orbit

6
这是绝对错误的。您不确定返回“ strReturn”时异步调用已完成。
托马斯·弗里茨

61
这是一个同步调用(async:false)。
詹姆斯indy 2012年

85

所有这些答案都忽略了要点,即使用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();
}

4
如果您想为REST后端建立快速测试工具,并且希望简单而不是回调地狱,那么同步调用非常方便。
Distortum 2014年

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


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

10
但是请注意,您可能会得到以下信息:“不赞成在主线程上使用同步XMLHttpRequest,因为它对最终用户的体验有不利影响。”
哈里2015年

5
@Hari在不使用主线程的情况下使用jQuery执行同步ajax调用的方法是什么?
Jose Nobile

7
我看不出这个答案有什么可提供的,只是包装在函数中并在四年后回答的被接受的答案。劝告人们使用C + P是一件坏事,因为该函数并不表示其功能。“那么,getURLVS get?为什么有人挂我的浏览器?” 等
moopet

27

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

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

Chrome甚至会在控制台中对此发出警告:

不赞成在主线程上使用同步XMLHttpRequest,因为它会对最终用户的体验产生不利影响。如需更多帮助,请访问https://xhr.spec.whatwg.org/

如果您正在执行此类操作,则可能会中断您的页面,因为它可能会在一天中停止工作。

如果您想以一种仍然是同步的方式但仍不阻塞的方式进行操作,则应该使用async / await,还可能使用一些基于诸如新Fetch API之类的诺言的ajax

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

当用户导航离开或关闭页面时,Edit chrome正在处理“ 禁止在页面关闭中同步XHR”。这涉及到卸载,卸载,页面隐藏和可见性更改。

如果这是你的使用情况,那么你可能想看看navigator.sendBeacon代替

页面也可能会禁用带有HTTP标头或iframe的allow属性的同步请求


请注意,您应该将await fetch(url)调用包装在一个try... catch块中,以捕获所有异步错误。
inostia

4
函数foo已经被刚刚用这个词转化为一个承诺async在开始的时候,所以你可以只是做foo().catch(...)赶上它也
无尽

Chrome浏览器已经禁止在页面内部使用异步Ajax,beforeunload但是在出现负反馈bugs.chromium.org/p/chromium/issues/detail?id=952452
Alex

26

请记住,如果您正在执行跨域Ajax调用(通过使用JSONP)-您无法同步进行,则asyncjQuery将忽略该标志。

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

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

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

12

有了async: false您,您自己的浏览器就会被封锁。对于非阻塞同步解决方案,可以使用以下方法:

ES6 / ECMAScript2015

使用ES6,您可以使用generator和co库

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 await:

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
    })(); 
}

3
注意,您可以传递async function给beforecreate beforecreate: async function(....并删除自我调用的异步函数
Daniel Krom,

12

我使用了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 work
    var 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'数据类型,并将.responseText更改为responseJSON

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

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

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

我也用POST进行了尝试,并且有效。

我将GET更改为POST并添加了数据: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 work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}

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


7

这是示例:

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

1
async false与基于承诺的解决方案一起使用的目的是什么?这只会锁定浏览器,根本没有任何好处。
Gone Coding

2
@GoneCoding在某些情况下希望按正确的顺序执行代码,在这种情况下,我们可以使用异步false
Nikki

1
@Nikki:绝对不是按顺序运行它们的方法。使用异步诺言(ajax已返回调用)和.then()done()(如已显示)。锁定浏览器是非常糟糕的用户体验。正如我async: false在本示例中所说的那样,这完全是浪费时间。
Gone Coding

4

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

当我们需要对ajax请求进行低级控制时,例如请求标头设置,缓存设置,同步设置等,那么我们应该选择$ .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
    });

2

这是我对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();

2

由于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;
};

-1

由于原来的问题是关于jQuery.get,值得一提的是这里(提到这里)一个可以使用async: false$.get(),但最好避免它,因为异步XMLHTTPRequest被弃用(和浏览器可以给予警告):

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

1
为什么这被否决?
alias51

-2

设置asyn:falseajax请求以使其同步。

这是代码示例:

 $.ajax({
    url: 'some_url',
    type: "GET",
    async: false,
    cache: false,
    dataType: "JSON",
    data: { 
      "p1": v1, 
      "p2": v2
    },
    success: function(result) {
    }  
  }
});

这会使屏幕无响应。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.