繁体   English   中英

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

[英]How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?

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

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

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

jQuery.ajaxSetup({async:false});

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

然后再打开一次

jQuery.ajaxSetup({async:true});

我想它的效果与@Adam 所建议的相同,但对于确实想要将其jQuery.get()jQuery.post()重新配置为更复杂的jQuery.ajax()语法的人来说,这可能会有所帮助。

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

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

所有这些答案都忽略了使用 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();
}
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


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

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

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

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

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

如果您正在执行此类操作,这可能会破坏您的页面,因为它可能在任何一天停止工作。

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

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.sendBeacon

页面也可以使用 http 标头或 iframe 的允许属性禁用同步请求

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

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

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

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

我使用了 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'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;
}

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

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

ES6/ECMAScript2015

使用 ES6,您可以使用生成器和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
    })(); 
}

这是示例:

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

首先我们应该了解什么时候使用$.ajax,什么时候使用$.get/$.post

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

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

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

这是我的“ Thread ”名称空间:

var Thread = {
    sleep: function(ms) {
        var start = Date.now();

        while (true) {
            var clock = (Date.now() - start);
            if (clock >= ms) break;
        }

    }
};

这就是我所说的:

var d1 = new Date();
console.log('start ' + d1.toLocaleTimeString());
Thread.sleep(10000);
var d2 = new Date();
console.log('end ' + d2.toLocaleTimeString());

如果查看控制台,我们将得到以下结果:

start 1:41:21 PM
end 1:41:31 PM

由于最初的问题是关于jQuery.get ,这里值得一提的是(正如这里提到的)可以$.get()使用async: false最好避免它,因为异步XMLHTTPRequest已被弃用(并且浏览器可能会给出一个警告):

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM