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


1207

У мене віджет 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 браузера?


30
Правильним способом вирішити це було б переписати обіцянки щодо використання розширення точки віджету. Цей спосіб легко дозволить вам налаштувати асинхронну дію (як запит ajax) як beforecreate.
Кос

3
Я пропоную функцію Саяка. У нас є літера Т? Так, Ванна, дай мені 3 Т.
Cody O'Dell

2
@Kos не ввімкнено. Синхронізувати XHR тут не потрібно
Майкл Весткотт

1
Якщо люди запитують мене за пораду при запуску javascript, я кажу: сприйміть асинхронний характер javascript, не намагайтеся боротися з цим.
Еммануель Затримка

3
Це питання схоже на запитання "як я зберігаю паролі користувачів у простому тексті?" Впевнені, що є відповідь, але не робіть цього.
Vectorjohn

Відповіді:


1165

З документації 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
    });
}

97
Точно неможливо використовувати get (), post (), load () для синхронних дзвінків. Тільки ajax () має параметр "async", який можна встановити на "false".
SLA80

39
@ SLA80 Ні. Так як JQuery 1.1: stackoverflow.com/questions/6849686 / ...
StuperUser

16
@qualidafial мій коментар спрямований на неправильний коментар SLA80; можна використовувати get (), post (), load () для синхронних дзвінків.
StuperUser

9
async false більше не підтримується для jQuery> = 1.8. Зверніться до api.jquery.com/jQuery.ajax
ken

22
@ken async: falseвсе ще підтримується у jQuery> = 1.8. Можливість використання async: falseз jqXHR ( $.Deferred) - це те, що застаріло. Іншими словами, необхідно використовувати нові успіху / помилки / повний набір опцій зворотного виклику, замість методів успадкованими, наприклад, jqXHR.done().
Бен Джонсон

255

Ви можете перевести налаштування Ajax jQuery в синхронний режим, зателефонувавши

jQuery.ajaxSetup({async:false});

А потім виконайте свої дзвінки Ajax за допомогою jQuery.get( ... );

Потім просто знову увімкніть його

jQuery.ajaxSetup({async:true});

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


56
Це дійсно погана ідея, чому б ви поставили її на глобальному рівні? А потім бути змушеним зняти це після?
Хуан Мендес

11
Принаймні, це найкраща погана ідея. замість того, щоб сказати: "ТАК НЕ ПОДАЄТЬСЯ $.ajax()". ;)
Rzassar

136

Відмінне рішення! Я помітив, коли намагався реалізувати це, що якщо я повернув значення в пункті про успіх, воно повернеться як невизначене. Мені довелося зберігати його у змінній та повертати цю змінну. Це метод, який я придумав:

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

16
Це тому, що ви повертали значення з зворотного дзвінка, а не з getWhatever. Таким чином, ви нічого не повернули, тобто undefinedзі свого getWhatever.
Гонки легкості по орбіті

6
це абсолютно неправильно. Ви не можете бути впевнені, що асинхронний дзвінок закінчився, коли повертаєте "strReturn".
Томас Фріц

61
Це синхронний виклик (async: false).
Джеймс в Інді

85

Усі ці відповіді пропускають те, що виконання дзвінка 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();
}

4
Синхронні дзвінки зручні, якщо ви хочете скласти швидкий тестовий джгут для задньої частини REST і віддаєте перевагу простоті в пеклі.
Distortum

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


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

10
Зауважте, що, однак, ви можете отримати таке: "Синхронний XMLHttpRequest в головному потоці застарілий через його згубний вплив на кінцевого користувача."
Харі

5
@Hari Який спосіб виконати синхронний ajax-дзвінок за допомогою jQuery без використання основної нитки?
Хосе Нобіле

7
Я не бачу, що ця відповідь може запропонувати що-небудь, це лише прийнята відповідь, яка зафіксована у функції і відповіла через чотири роки. Погано радити людям C + P, оскільки функція не вказує, що вона робить. "Так getURLпорівняно get? Чому один підвішує мій браузер?" пр.
moopet

27

Примітка. Не слід використовувати async: falseчерез це попередження:

Починаючи з Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), синхронні запити на головному потоці були вимкнені через негативні наслідки для роботи користувачів.

Chrome навіть попереджає про це в консолі:

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

Це може зламати вашу сторінку, якщо ви робите щось подібне, оскільки це може перестати працювати в будь-який день.

Якщо ви хочете зробити це таким чином, як і раніше, схоже, що це синхронно, але все-таки не блокується, тоді вам слід використовувати async / wait і, ймовірно, також якийсь аякс, який базується на обіцянках, як новий API Fetch

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


Зауважте, що ви повинні загортати свій await fetch(url)дзвінок у try... catchблок, щоб отримати будь-які асинхронні помилки.
inostia

4
функція foo була перетворена на обіцянку, просто використовуючи слово asyncна початку, так що ви можете просто зробити, foo().catch(...)щоб також його зловити
Endless

Chrome вже заборонив async ajax на внутрішній сторінці, beforeunloadале потім повернув зміни після негативних відгуків bugs.chromium.org/p/chromium/isissue/detail?id=952452
Alex

26

Майте на увазі, що якщо ви здійснюєте міждоменний дзвінок Ajax (за допомогою JSONP ) - ви не можете це робити синхронно, asyncjQuery прапор буде ігнорувати.

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

Для дзвінків JSONP ви можете використовувати:

  1. Ajax-виклик до вашого власного домену - і виконайте міждоменний дзвінок на стороні сервера
  2. Змініть код, щоб він працював асинхронно
  3. Використовуйте бібліотеку "послідовника функцій" на зразок Frame.js (ця відповідь )
  4. Блокуйте інтерфейс користувача замість блокування виконання (ця відповідь ) (мій улюблений спосіб)

12

З async: falseвами ви отримуєте заблокований браузер. Для синхронного рішення, що не блокує, ви можете використовувати наступне:

ES6 / ECMAScript2015

За допомогою ES6 ви можете використовувати генератор та спільну бібліотеку :

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 в очікуванні:

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

3
Зауважте, що ви можете просто перейти async functionдо створення beforecreate: async function(....та видалення самозваної функції асинхронізації
Даніель Кром

12

Я використав відповідь, яку дав Карсіоне, і модифікував її для використання 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" і змінив .responseText на responseJSON .

Я також отримав статус, використовуючи властивість statusText повернутого об'єкта. Зауважте, що це статус відповіді Аякса, а не те, чи дійсний 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: true повернутий об'єкт jqxhr не був би дійсним під час повернення виклику AJAX, лише пізніше, коли асинхронний виклик закінчився, але це набагато пізно для встановлення змінної відповіді .


7

Це приклад:

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

1
В чому сенс використання async falseрішення, засноване на обіцянках. Це блокує браузер лише без користі.
Пройшов кодування

2
@GoneCoding є ситуації, коли хочеться виконати код у точній послідовності, і в цій ситуації ми можемо використовувати async false
Nikki

1
@Nikki: Це абсолютно не спосіб послідовно запускати їх. Використання асинхронних обіцянок (що ajaxвиклики вже повернутися) та .then()чи done()(як це вже показує). Блокування веб-переглядача - дуже поганий досвід користувача. Як я вже казав, наявність async: falseу цьому прикладі - це повна трата часу.
Пройшов кодування

4

По-перше, ми повинні розуміти, коли ми використовуємо $ .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
    });

2

це моя проста реалізація для запитів 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

Оскільки 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;
};

-1

Оскільки вихідний питання було про те jQuery.get, що варто згадати , що (як уже згадувалося тут ) один міг використовувати async: falseв $.get()але в ідеалі уникнути його , так як асинхронна XMLHTTPRequestє застарілим (і браузер може дати попередження):

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

1
чому це заборонено?
alias51

-2

Встановіть asyn:falseу ajax запит, щоб зробити його синхронним.

Ось зразок коду:

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

Це може зробити екран невідповідним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.