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

Art*_*rov 1173 javascript ajax jquery asynchronous

我有一个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);
  });
}
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*ire 1133

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
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 确切地说,不可能对同步调用使用get(),post(),load().只有ajax()具有"async"参数,可以设置为"false". (97认同)
  • @ SLA80不.从jQuery 1.1开始:http://stackoverflow.com/questions/6849686/how-to-change-ajax-default-settings (38认同)
  • jQuery> = 1.8仍支持@ken`async:false`.使用`async:false`和jqXHR(`$ .Deferred`)的能力是不赞成使用的.换句话说,必须使用较新的成功/错误/完整回调选项,而不是遗留方法,例如``jqXHR.done()`. (22认同)
  • @qualidafial我的评论是针对SLA80的错误评论; 可以使用get(),post(),load()进行同步调用. (15认同)
  • jQuery> = 1.8不再支持async false.请参阅api.jquery.com/jQuery.ajax (8认同)
  • 只是一个注释,添加`async:false`对我来说很有用,只要我将整个ajax函数设置为某个变量的值.例如,`var ajaxresults = $ .ajax({....` (5认同)
  • 请注意,“async: false”的使用已[弃用](/sf/ask/1941533051/?rq=1)。如果您使用它,您将在控制台中看到以下消息:“主线程上的同步 XMLHttpRequest 已被弃用,因为它会对最终用户的体验产生不利影响。有关更多帮助,请访问 http://xhr.spec.whatwg.org/ ” (4认同)
  • @Ikbel:不,请参阅本·约翰逊的评论。它已与$ .Deferred`结合使用,而不是单独使用。 (2认同)
  • 需要注意的重要事项是jQuery> 3.0的较新版本不建议使用`async:false`选项。因此,该方法无法实现。 (2认同)

Syd*_*ell 251

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

jQuery.ajaxSetup({async:false});
Run Code Online (Sandbox Code Playgroud)

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

然后再打开一次

jQuery.ajaxSetup({async:true});
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一个非常糟糕的主意,为什么要在全球范围内设置它?之后被迫取消它? (56认同)
  • 至少,这是最好的坏主意.而不是说:"除了`$ .ajax()`"之外没有办法.;) (8认同)

Jam*_*ndy 135

优秀解决方案 我注意到当我尝试实现它时,如果我在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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是同步调用(async:false). (61认同)
  • 那是因为你从回调中返回一个值,而不是`getWhatever`.因此你从`getWhatever`返回_nothing_ ie`undefined`. (16认同)
  • 这是绝对错误的.返回'strReturn'时,无法确定异步调用是否已完成. (6认同)

Bis*_*opZ 84

所有这些答案都忽略了使用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();
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你想为REST后端组装一个快速测试工具并且希望简单而不是回调地狱,同步调用很方便. (4认同)

小智 50

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


//example use
var msg=getURL("message.php");
alert(msg);
Run Code Online (Sandbox Code Playgroud)

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

Ser*_*ltz 25

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

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

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

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


End*_*ess 24

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

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

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

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

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

如果你想这样做仍然感觉如果它是同步但仍然没有阻塞那么你应该使用async/await,也许还有一些基于promises的ajax,比如新的Fetch API

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}
Run Code Online (Sandbox Code Playgroud)

当页面被用户导航或关闭时,编辑 Chrome正在处理禁止同步XHR的页面解雇.这涉及beforeunload,unload,pagehide和visibilitychange.

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

页面也可以使用http标头或iframe的allow属性禁用sync req

  • 函数foo已经通过在开头使用单词"async"转换为promise,所以你可以做`foo().catch(...)`来捕获它 (3认同)

pau*_*o62 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');
    }    
}
Run Code Online (Sandbox Code Playgroud)

我添加了'JSON'dataType,并将.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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,上述代码仅适用于asyncfalse的情况.如果要设置async:true,则返回的对象jqxhr在AJAX调用返回时无效,仅在异步调用结束后才有效,但设置响应变量为时已晚.


Spe*_*pen 12

随着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
    });
}
Run Code Online (Sandbox Code Playgroud)

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
    })(); 
}
Run Code Online (Sandbox Code Playgroud)

  • 注意你可以通过`async function`传递给beforecreate:beforecreate:async function(....`并删除自调用异步函数 (3认同)

sea*_*g9x 7

这是一个例子:

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

  • @GoneCoding在某些情况下希望按准确的顺序执行代码,在这种情况下,我们可以使用async false (2认同)

小智 6

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

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();
Run Code Online (Sandbox Code Playgroud)


She*_*ngh 5

首先我们要明白什么时候用$.ajax,什么时候用$.get/$.post

当我们需要对 ajax 请求进行底层控制时,例如请求头设置、缓存设置、同步设置等,那么我们应该选择 $.ajax。

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

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});
Run Code Online (Sandbox Code Playgroud)

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

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

 $.ajax({
     type: 'GET',
      url: url,
      data: data,
      success: success,
      dataType: dataType,
      async:false
    });
Run Code Online (Sandbox Code Playgroud)


Geo*_*rey 5

因为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;
};
Run Code Online (Sandbox Code Playgroud)