Как я могу заставить 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 в браузере?

25.09.2008 13:26:54
Правильный способ решить эту проблему - переписать обещания точки расширения вашего виджета. Этот способ позволит вам легко настроить асинхронное действие (например, запрос ajax) как beforecreate.
Kos 22.12.2013 11:32:41
Я предлагаю функцию Саджак. У нас есть буква Т? Да, Ванна, дай мне 3 Ти.
Cody O'Dell 14.04.2016 00:18:13
@Kos на месте. Синхронизация XHR здесь не требуется
Michael Westcott 9.10.2016 10:47:25
Если при запуске javascript меня попросят дать один совет, я скажу: примите асинхронный характер javascript, не пытайтесь бороться с этим.
Emmanuel Delay 14.12.2017 11:55:46
Этот вопрос похож на вопрос: «Как мне сохранить мои пароли пользователей в виде простого текста?» Конечно, есть ответ, но не делайте этого.
Vectorjohn 29.10.2018 23:04:44
15 ОТВЕТОВ
РЕШЕНИЕ

Из документации 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
    });
}
1161
21.11.2015 12:20:02
Точно, невозможно использовать get (), post (), load () для синхронных вызовов. Только ajax () имеет параметр «async», который может быть установлен в «false».
SLA80 16.05.2010 11:41:21
@ SLA80 Нет. Начиная с jQuery 1.1: stackoverflow.com/questions/6849686/…
StuperUser 1.08.2011 17:45:25
@qualidafial мой комментарий нацелен на неправильный комментарий SLA80; можно использовать get (), post (), load () для синхронных вызовов.
StuperUser 8.03.2012 18:00:16
async false больше не поддерживается для jQuery> = 1.8. Обратитесь к api.jquery.com/jQuery.ajax
ken 5.08.2015 08:43:03
@ken async: falseвсе еще поддерживается в jQuery> = 1.8. Возможность использовать async: falseс jqXHR ( $.Deferred) - это то, что устарело. Другими словами, необходимо использовать новые успеха / ошибки / полный набор опций обратного вызова, вместо методов унаследованными, например, jqXHR.done().
Ben Johnson 30.10.2015 14:09:02

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

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;
}
136
30.03.2018 21:25:14
Это потому, что вы возвращали значение из обратного вызова, а не из getWhatever. Таким образом, вы ничего не вернули, т.е. undefinedот своего getWhatever.
Lightness Races in Orbit 11.07.2011 23:35:29
это абсолютно неправильно. Вы не можете быть уверены, что асинхронный вызов завершился при возврате 'strReturn'.
Thomas Fritz 22.02.2012 11:30:54
Это синхронный вызов (async: false).
James in Indy 5.03.2012 18:13:06

Вы можете перевести установку Ajax в JQuery в синхронный режим, вызвав

jQuery.ajaxSetup({async:false});

А затем выполните ваши вызовы Ajax, используя jQuery.get( ... );

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

jQuery.ajaxSetup({async:true});

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

255
30.03.2018 21:25:00
Это действительно плохая идея, зачем вы устанавливаете ее на глобальном уровне? А потом будет вынужден сбросить его после?
Juan Mendes 4.08.2014 18:16:30
По крайней мере, это лучшая плохая идея. вместо того, чтобы говорить: «НЕТ, ИСКЛЮЧЕНО $.ajax()». ;)
Rzassar 31.05.2016 03:22:23
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);
50
25.04.2012 15:34:38
Однако обратите внимание, что вы можете получить следующее: «Синхронный XMLHttpRequest в основном потоке устарел из-за его пагубных последствий для конечного пользователя».
Hari 7.05.2015 20:09:39
@Hari Как выполнить синхронный вызов ajax с использованием jQuery без использования основного потока?
Jose Nobile 9.02.2016 21:29:41
Я не вижу, чтобы этот ответ что-то предлагал, это просто принятый ответ, заключенный в функцию и отвеченный четыре года спустя. Плохо советовать людям C + P, потому что функция не указывает, что она делает. "Так getURLпротив get? Почему один повесить мой браузер?" и т.д.
moopet 26.10.2016 10:13:04

Во всех этих ответах упущено, что выполнение вызова 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();
}
85
21.11.2015 12:23:10
Синхронные вызовы удобны, если вы хотите собрать быстрый тестовый комплект для REST-сервера и предпочли бы простоту аду обратного вызова.
Distortum 19.05.2014 02:08:45

Это пример:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});
7
16.08.2014 13:20:10
Какой смысл использовать async falseрешение на основе обещаний. Это только блокирует браузер без какой-либо выгоды.
Gone Coding 5.09.2017 18:22:55
@GoneCoding есть ситуации, когда нужно выполнить код в точной последовательности, в этой ситуации мы можем использовать асинхронный false
Nikki 6.10.2017 12:05:31
@Nikki: Это абсолютно не способ запустить их последовательно. Используйте асинхронные обещания ( ajaxвызовы которых уже возвращаются) и .then()или done()(как это уже показано). Блокировка браузера - очень плохой пользовательский опыт. Как я уже сказал, наличие async: falseв этом примере - пустая трата времени.
Gone Coding 6.10.2017 21:38:22

Я использовал ответ, данный 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 имеет значение false . Если бы вы установили async: true, возвращаемый объект jqxhr был бы недействительным во время возврата вызова AJAX, только позже, когда асинхронный вызов завершился, но это слишком поздно для установки переменной ответа .

12
30.03.2018 21:25:39

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

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

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

  1. Ajax-вызов в ваш собственный домен и выполнение междоменного вызова на стороне сервера
  2. Измените свой код для асинхронной работы
  3. Используйте библиотеку "Function sequencer", такую ​​как Frame.js (этот ответ )
  4. Блокировать пользовательский интерфейс вместо блокировки выполнения (этот ответ ) (мой любимый способ)
26
30.06.2017 07:24:05

С 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
    })(); 
}
12
20.08.2016 19:52:07
Обратите внимание, что вы можете просто перейти async functionк beforecreate beforecreate: async function(....и удалить асинхронную функцию, вызываемую самим собой
Daniel Krom 7.05.2018 16:05:24

Примечание: вы не должны использовать 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, либо с атрибутом allow iframe.

27
19.02.2019 13:02:46
Обратите внимание, что вы должны заключить ваш await fetch(url)вызов в try... catchблок, чтобы перехватить любые асинхронные ошибки.
inostia 19.04.2017 21:39:15
функция foo была преобразована в обещание, просто используя слово asyncв начале, так что вы можете просто foo().catch(...)поймать его
Endless 20.04.2017 08:47:38
Chrome уже запретил асинхронный ajax внутри страницы, beforeunloadно затем отменил изменение обратно после отрицательного отзыва bugs.chromium.org/p/chromium/issues/detail?id=952452
Alex 20.06.2019 10:45:05

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

это моя простая реализация запросов 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();
2
15.02.2018 19:55:31

Поскольку 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;
};
2
29.04.2018 13:30:01

Поскольку первоначальный вопрос был о том jQuery.get, стоит упомянуть здесь, что (как упомянуто здесь ) можно использовать async: falseв, $.get()но в идеале избегать этого, поскольку асинхронный XMLHTTPRequestустаревший (и браузер может выдавать предупреждение):

$.get({
  url: url,// mandatory
  data: data,
  success: success,
  dataType: dataType,
  async:false // to make it synchronous
});
-1
11.01.2020 17:10:15

Установите asyn:falseзапрос ajax, чтобы сделать его синхронным.

Вот пример кода:

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

Это может сделать экран не отвечает.

-2
31.01.2020 23:03:59