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

StackOverflow https://stackoverflow.com/questions/133310

Вопрос

У меня есть виджет 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?

Это было полезно?

Решение

Из самого Документация по jQuery:вы указываете асинхронный возможность быть ложь чтобы получить синхронный 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
    });
}

Другие советы

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

jQuery.ajaxSetup({async:false});

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

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

jQuery.ajaxSetup({async:true});

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

Отличное решение!Я заметил, когда пытался это реализовать, что если я возвращал значение в предложении 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;
}

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


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

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

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

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

  1. Ajax-вызовите свой собственный домен - и выполните междоменный вызов на стороне сервера
  2. Измените свой код, чтобы он работал асинхронно
  3. Используйте библиотеку "function sequencer", подобную Frame.js (это ответ)
  4. Блокируйте пользовательский интерфейс вместо блокирования выполнения (это ответ) (мой любимый способ)

Примечание:Вам не следует использовать async: false из-за этого появляются предупреждающие сообщения:

Начиная с версии Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), синхронные запросы в основном потоке устарели из-за негативного влияния на работу пользователя.

Chrome даже предупреждает об этом в консоли:

Синхронный XMLHttpRequest в основном потоке устарел из-за его пагубного воздействия на работу конечного пользователя.Для получения дополнительной информации проверьте https://xhr.spec.whatwg.org/.

Это может привести к поломке вашей страницы, если вы делаете что-то подобное, поскольку она может перестать работать в любой день.

Если вы хотите сделать это так, чтобы все еще казалось, что это синхронно, но все еще не блокируется, тогда вам следует использовать async / await и, вероятно, также некоторый ajax, основанный на обещаниях, таких как new Принести 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.

если это ваш вариант использования, то вы, возможно, захотите взглянуть на навигатор.Отправить сообщение вместо этого

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

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

Я использовал ответ, данный 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' и изменил .Текст ответа Для Ответјсон.

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

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

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

Я также попробовал это с POST, и это сработало.

Я изменил GET на POST и добавил данные:постданные

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

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

Это пример:

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

Во-первых, мы должны понимать, когда мы используем $.ajax и когда мы используем $.get / $.post

Когда нам требуется низкоуровневый контроль над ajax-запросом, такой как настройки заголовка запроса, настройки кэширования, синхронные настройки и т.д., тогда мы должны использовать $.ajax.

$.получить/$.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
    });

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

Потому что 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;
};

Это мой “Нитки” пространство имен:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top