Jak mogę zmusić jQuery do wykonania synchronicznego, a nie asynchronicznego żądania Ajax?

Mam widget JavaScript, który zapewnia standardowe punkty rozszerzeń. Jedną z nich jest funkcja beforecreate. Powinien zwrócić false, aby zapobiec utworzeniu elementu.

Dodałem wywołanie Ajax do tej funkcji przy użyciu 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);
  });
}

Ale chcę, aby mój widget nie tworzył elementu, więc powinienem zwrócić false w funkcji matki, a nie w wywołaniu zwrotnym. Czy istnieje sposób na wykonanie synchronicznego żądania AJAX przy użyciu jQuery lub innego API w przeglądarce?

Author: Artem Tikhomirov, 2008-09-25

13 answers

Z jQuery documentation: podajesz asynchroniczną opcję false, aby uzyskać synchroniczne żądanie Ajax. Wtedy twój callback może ustawić pewne dane, zanim twoja matka zacznie działać.

Oto jak wyglądałby Twój kod, gdyby został zmieniony zgodnie z sugestią:

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
    });
}
 1048
Author: Adam Bellaire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-21 12:20:02

Możesz umieścić konfigurację Ajax jQuery w trybie synchronicznym, wywołując

jQuery.ajaxSetup({async:false});

A następnie wykonaj połączenia Ajax używając jQuery.get( ... );

Następnie włącz go ponownie raz

jQuery.ajaxSetup({async:true});

Wydaje mi się, że działa to tak samo, jak sugeruje to @Adam, ale może to być pomocne dla kogoś, kto chce zmienić swoją jQuery.get() lub jQuery.post() na bardziej rozbudowaną składnię jQuery.ajax().

 239
Author: Sydwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 21:25:00

Doskonałe rozwiązanie! Zauważyłem, gdy próbowałem go zaimplementować, że jeśli zwróciłem wartość w klauzuli sukcesu, wróciła jako niezdefiniowana. Musiałem zapisać go w zmiennej i zwrócić tę zmienną. Jest to metoda, którą wymyśliłem:

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;
}
 128
Author: James in Indy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 21:25:14

Wszystkie te odpowiedzi pomijają to, że wywołanie Ajax z async: false spowoduje zawieszenie przeglądarki do czasu zakończenia żądania Ajax. Korzystanie z biblioteki kontroli przepływu rozwiąże ten problem bez rozłączania przeglądarki. Oto przykład z 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();
}
 82
Author: BishopZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-21 12:23:10
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);
 49
Author: Carcione,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-25 15:34:38

Pamiętaj, że jeśli wykonujesz między domenowe wywołanie Ajax (używając JSONP ) - nie możesz zrobić tego synchronicznie, flagaasync zostanie zignorowana przez jQuery.

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

Dla połączeń JSONP można użyć:

    Ajax-połączenie do własnej domeny - i wykonywanie połączeń między domenami po stronie serwera
  1. Zmień kod na asynchronicznie
  2. użyj biblioteki "sekwencer funkcji", takiej jak ramka.js (this answer )
  3. blokowanie interfejsu użytkownika zamiast blokowanie wykonania (this answer ) (my favourite way)
 22
Author: Serge Shultz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-30 07:24:05

Uwaga: nie powinieneś używać asynchronizacji z tego powodu:

Począwszy od Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), synchroniczne żądania w głównym wątku zostały wycofane ze względu na negatywny wpływ na doświadczenie użytkownika.

Chrome ostrzega nawet o tym w konsoli:

Synchroniczne XMLHttpRequest w głównym wątku jest przestarzałe ze względu na jego szkodliwy wpływ na doświadczenie użytkownika końcowego. Aby uzyskać więcej pomocy, sprawdź https://xhr.spec.whatwg.org/.

To może złamać stronę, jeśli robisz coś takiego, ponieważ może przestać działać lada dzień.

Jeśli chcesz zrobić to w sposób, który nadal wydaje się synchroniczny, ale nadal nie blokuje, powinieneś użyć async / wait I prawdopodobnie również ajax, który jest oparty na obietnicach, takich jak NOWY Fetch API

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}
 19
Author: Endless,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-13 20:04:51

Użyłem odpowiedzi udzielonej przez Carcione i zmodyfikowałem ją na 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');
    }    
}

Dodałem dataType z 'JSON' i zmieniłem .responseText do responseJSON.

Odzyskałem również status używając właściwości statusText zwracanego obiektu. Zauważ, że jest to stan odpowiedzi Ajax, a nie to, czy JSON jest poprawny.

Back-end musi zwracać odpowiedź w poprawnym (dobrze uformowanym) JSON, w przeciwnym razie zwracany obiekt będzie niezdefiniowany.

Są dwa aspekty, które należy wziąć pod uwagę, odpowiadając na pierwotne pytanie. Jeden mówi Ajaxowi, aby działał synchronicznie (ustawiając async: false), a drugi zwraca odpowiedź za pomocą instrukcji return funkcji wywołującej, a nie do funkcji zwrotnej.

Próbowałem też z postem i zadziałało.

Zmieniłem GET to POST i dodałem Dane: 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;
}

Zauważ, że powyższy kod działa tylko w przypadek, w którym async jest false . Jeśli ustawisz async: true zwracany obiekt jqxhrnie będzie ważny w momencie, gdy wywołanie AJAX zostanie zwrócone, dopiero później, gdy wywołanie asynchroniczne zostanie zakończone, ale jest to o wiele za późno, aby ustawić zmienną response.

 10
Author: paulo62,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 21:25:39

Z async: false dostajesz zablokowaną przeglądarkę. Dla nieblokującego rozwiązania synchronicznego można użyć następującego:

ES6 / ECMAScript2015

Z ES6 możesz użyć generatora i biblioteki 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

Z ES7 możesz po prostu użyć 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
    })(); 
}
 9
Author: Spen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-20 19:52:07

Oto przykład:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});
 6
Author: searching9x,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-16 13:20:10

Po pierwsze powinniśmy zrozumieć kiedy używamy $.ajax i kiedy używamy $.get/$.post

Gdy wymagamy niskiego poziomu kontroli nad żądaniem ajax, takim jak ustawienia nagłówka żądania, ustawienia buforowania, ustawienia synchroniczne itp.więc powinniśmy iść za $.ajax.

$.get/$.post: gdy nie wymagamy niskiego poziomu kontroli nad żądaniem ajax.Tylko proste get/post danych do serwera.jest skrótem

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

I dlatego nie możemy korzystać z innych funkcji (synchronizacja, cache itd.) z $.get/$.poczta.

Stąd do kontroli niskiego poziomu (synchronizacja, pamięć podręczna itp.) nad żądaniem ajax, powinniśmy przejść do $.ajax

 $.ajax({
     type: 'GET',
      url: url,
      data: data,
      success: success,
      dataType: dataType,
      async:false
    });
 2
Author: Sheo Dayal Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 09:52:59

To jest moja prosta implementacja dla żądań asynchronicznych z jQuery. Mam nadzieję, że to komuś pomoże.

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();
 0
Author: Felipe Marques,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-15 19:55:31

Ponieważ XMLHttpReponse synchroniczne działanie jest przestarzałe, wymyśliłem następujące rozwiązanie, które zawija XMLHttpRequest. Pozwala to na uporządkowanie zapytań AJAX, a jednocześnie ma charakter asycnronous, co jest bardzo przydatne w przypadku jednorazowych tokenów CSRF.

Jest również przezroczysty, więc biblioteki takie jak jQuery będą działać bezproblemowo.

/* 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;
};
 0
Author: Geoffrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-29 13:30:01