题 如何让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请求?


1052
2017-09-25 13:26


起源


解决这个问题的正确方法是重写小部件的扩展点使用承诺。这种方式很容易让您设置异步操作(如ajax请求) beforecreate。 - Kos
我提出了Sajak功能。我们有一封字母T吗?是vanna,给我3 T。 - Cody O'Dell
@Kos就是现货。此处不需要同步XHR - Michael Westcott
如果人们在启动javascript时问我一条建议,我说:拥抱javascript的异步字符,不要尝试ty打那个。 - Emmanuel Delay
你可以尝试使用 embeddedjs.com - firstpostcommenter


答案:


来自 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
    });
}

1034
2017-09-25 13:30



确切地说,不可能对同步调用使用get(),post(),load()。只有ajax()具有“async”参数,可以设置为“false”。 - SLA80
@ SLA80不。从jQuery 1.1开始: stackoverflow.com/questions/6849686/... - StuperUser
@qualidafial我的评论针对的是SLA80的错误评论;可以使用get(),post(),load()进行同步调用。 - StuperUser
jQuery> = 1.8不再支持async false。请参阅api.jquery.com/jQuery.ajax - ken
@ken async: false 仍然支持jQuery> = 1.8。使用的能力 async: false 与jqXHR($.Deferred)是被弃用的东西。换句话说,必须使用较新的成功/错误/完整回调选项,而不是传统方法,例如, jqXHR.done()。 - Ben Johnson


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

jQuery.ajaxSetup({async:false});

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

然后再打开一次

jQuery.ajaxSetup({async:true});

我想这与@Adam所建议的相同,但它可能对想要重新配置它们的人有所帮助 jQuery.get() 要么 jQuery.post() 更精致 jQuery.ajax() 句法。


237
2018-04-12 21:45



这是一个非常糟糕的主意,为什么要在全球范围内设置它?之后被迫取消它? - Juan Mendes
至少,这是最好的坏主意。而不是说:“没有办法除外 $.ajax()“。;) - Rzassar
不应全局设置.. - 0kay


优秀解决方案我注意到当我尝试实现它时,如果我在success子句中返回了一个值,那么它将返回undefined。我必须将它存储在变量中并返回该变量。这是我提出的方法:

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

125
2018-04-07 13:30



那是因为你从回调中返回了一个值,而不是从回调中返回 getWhatever。因此你回来了 没有 即 undefined 从你的 getWhatever。 - Lightness Races in Orbit
这是绝对错误的。返回'strReturn'时,无法确定异步调用是否已完成。 - Thomas Fritz
这是一个同步调用(async:false)。 - James in Indy


所有这些答案都错过了使用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();
}

82
2018-04-28 17:41



如果你想为REST后端组装一个快速测试工具并且希望简单而不是回调地狱,同步调用很方便。 - Steve Taylor


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


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

49
2018-04-25 15:34



但请注意,您可能会得到这样的结论:'主线程上的同步XMLHttpRequest因其对最终用户体验的不利影响而被弃用。 - Hari
@Hari在不使用主线程的情况下使用jQuery执行同步ajax调用的方法是什么? - Jose Nobile
我没有看到这个答案有什么可以提供的,它只是被接受的答案包含在一个功能中,并在四年后回答。向人们建议C + P是一件坏事,因为该功能并没有表​​明它的作用。 “所以 getURL VS get ?为什么要挂我的浏览器?“等等 - moopet


请记住,如果您正在进行跨域Ajax调用(通过使用 JSONP) - 你 不能 同步做, async jQuery会忽略flag。

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

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

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

22
2018-05-10 06:28





注意:由于这个原因,您不应该使用async:

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

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

主线程上的同步XMLHttpRequest由于其对最终用户体验的不利影响而被弃用。如需更多帮助,请查看 https://xhr.spec.whatwg.org/

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

如果你想这样做仍然感觉如果它是同步但仍然没有阻塞那么你应该使用async / await并且可能还有一些基于promises的ajax  API

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

17
2017-12-13 12:55



请注意,你应该包装你的 await fetch(url) 打电话给 try... catch 阻止捕获任何异步错误。 - inostia
函数foo已经通过使用单词转换为promise async 在一开始,所以你可以这样做 foo().catch(...) 抓住它也 - Endless


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等待:

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

9
2017-08-20 19:52



请注意,你可以通过 async function 之前创造 beforecreate: async function(.... 并删除自调用的异步函数 - Daniel Krom