Как я могу заставить jQuery выполнять синхронный, а не асинхронный Ajax-запрос? - PullRequest
1147 голосов
/ 25 сентября 2008

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

Ответы [ 14 ]

1106 голосов
/ 25 сентября 2008

Из документации 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
    });
}
248 голосов
/ 13 апреля 2011

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

jQuery.ajaxSetup({async:false});

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

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

jQuery.ajaxSetup({async:true});

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

133 голосов
/ 07 апреля 2010

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

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;
}
83 голосов
/ 28 апреля 2012

Во всех этих ответах упущено, что выполнение вызова 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();
}
49 голосов
/ 25 апреля 2012
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);
24 голосов
/ 10 мая 2015

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

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

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

  1. Ajax-вызов в ваш собственный домен и выполнение междоменного вызова на стороне сервера
  2. Измените свой код на асинхронную работу
  3. Использовать библиотеку "функции-секвенсора", такую ​​как Frame.js (этот ответ )
  4. Блокировать пользовательский интерфейс вместо блокировки выполнения (это ответ ) (мой любимый способ)
23 голосов
/ 13 декабря 2016

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

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

11 голосов
/ 20 августа 2016

С 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
    })(); 
}
11 голосов
/ 15 ноября 2014

Я использовал ответ, данный Карсионе, и изменил его, чтобы использовать 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 и добавил data: 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, только позже, когда завершился асинхронный вызов, но это слишком поздно установить переменную response .

6 голосов
/ 16 августа 2014

Это пример:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...