Как я могу получить jQuery для выполнения синхронного, а не асинхронного запроса Ajax?

У меня есть виджет JavaScript, который предоставляет стандартные точки расширения. Одна из них - это функция beforecreate. Он должен возвращать false чтобы предотвратить создание элемента.

Я добавил вызов Ajax в эту функцию, используя jQuery:

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 в функции mother, а не в обратном вызове. Есть ли способ выполнить синхронный запрос AJAX с использованием jQuery или любого другого API-интерфейса в браузере?

Ответ 1

Из документации 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
    });
}

Ответ 2

Вы можете установить jQuery Ajax в синхронном режиме, позвонив

jQuery.ajaxSetup({async:false});

Затем выполните ваши вызовы Ajax с помощью jQuery.get(... );

Затем просто включайте его снова

jQuery.ajaxSetup({async:true});

Я предполагаю, что это работает так же, как предложено @Adam, но может быть полезно кому-то, кто хочет перенастроить свои jQuery.get() или jQuery.post() в более сложный синтаксис jQuery.ajax().

Ответ 3

Отличное решение! Я заметил, что когда я попытался реализовать его, если бы я вернул значение в предложение success, оно вернулось как неопределенное. Мне пришлось хранить его в переменной и возвращать эту переменную. Это метод, который я придумал:

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

Ответ 4

Все эти ответы не согласны с тем, что выполнение Ajax-вызова с помощью async: false приведет к зависанию браузера, пока не будет завершен запрос 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();
}

Ответ 5

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


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

Ответ 6

Имейте в виду, что если вы выполняете междоменный вызов Ajax (используя JSONP) - вы не можете делать он синхронно, флаг async будет игнорироваться jQuery.

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

Для JSONP-вызовов вы можете использовать:

  • Ajax-вызов в ваш собственный домен - и выполните междоменный вызов на стороне сервера
  • Измените свой код для работы асинхронно
  • Используйте библиотеку "секвенсер функций", такую ​​как Frame.js(этот ответ)
  • Заблокируйте пользовательский интерфейс вместо блокировки выполнения (этот ответ) (мой любимый способ)

Ответ 7

Примечание: вы не должны использовать 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 при закрытии страницы, когда страница перемещается или закрывается пользователем. Это включает в себя загрузку, выгрузку, скрытие страниц и изменение видимости.

если это ваш вариант использования, вы можете вместо этого взглянуть на navigator.sendBeacon

Страница также может отключить синхронизацию req либо с заголовками http, либо с атрибутом iframe allow

Ответ 8

Я использовал ответ, данный 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');
    }    
}

Я добавил dataType 'JSON' и изменил .responseText на responseJSON.

Я также получил статус с использованием свойства statusText возвращаемого объекта. Обратите внимание, что это статус ответа Ajax, а не действителен ли JSON.

Внутренний сервер должен вернуть ответ в правильном (правильно сформированном) JSON, иначе возвращаемый объект будет неопределенным.

При ответе на исходный вопрос необходимо учитывать два аспекта. Один говорит Ajax выполнять синхронно (путем установки async: false), а другой возвращает ответ через оператор возврата функции вызова, а не в функцию обратного вызова.

Я также пробовал его с помощью 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;
}

Обратите внимание, что приведенный выше код работает только в случае, когда async является ложным. Если вы должны были установить async: true, возвращаемый объект jqxhr недействителен во время вызова AJAX, только позже, когда асинхронный вызов будет завершен, но слишком поздно установить переменную ответа.

Ответ 9

С async: false вы получаете заблокированный браузер. Для неблокирующего синхронного решения вы можете использовать следующее:

ES6/ECMAScript2015

С ES6 вы можете использовать генератор и co library:

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

Ответ 10

Это пример:

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

Ответ 11

Клиентский код JavaScript на JavaScript

function isValidLogin() {
    var flag = false;
    var Response = $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        url: "UPSLabelFormCA.aspx/IsValidLogin",
        async: false
    }).responseText;

    var toJson = jQuery.parseJSON(Response);
    if (toJson.d[0].Message == 'SUCCESS') {
        flag = true;
    }
    return flag;
}

Код сервера ASP.NET

[WebMethod]
public static List<ShipInfo> IsValidLogin()
{
    List<ShipInfo> loginStatus = new List<ShipInfo>();
    if (HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.Session["Email"] != null)
    {
        loginStatus.Add(new ShipInfo() { Success = true, Message = "SUCCESS" });
    }
    else
    {

        loginStatus.Add(new ShipInfo() { Success = false, Message = "FAILED" });
    }
    return loginStatus;

}

Ответ 12

Во-первых, мы должны понимать, когда мы используем $.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
    });

Ответ 13

это моя простая реализация для запросов ASYNC с помощью 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();

Ответ 14

Поскольку синхронная операция 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 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;
};

Ответ 15

Это мое пространство имен " 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