Jak sprawić, by jQuery czekało na zakończenie połączenia Ajax, zanim powróci?

Mam funkcję po stronie serwera, która wymaga logowania. Jeśli użytkownik jest zalogowany, funkcja zwróci 1 po pomyślnym zakończeniu. Jeśli nie, funkcja zwróci stronę logowania.

Chcę wywołać funkcję używając Ajax i jQuery. To, co robię, to przesyłanie żądania za pomocą zwykłego linku, z zastosowaną funkcją klikania. Jeśli użytkownik nie jest zalogowany lub funkcja nie powiedzie się, chcę, aby Ajax-call zwrócił true, tak, że href uruchamia.

Jednakże, kiedy używam po zakończeniu kodu funkcja kończy działanie przed wywołaniem Ajax.

Jak mogę przekierować użytkownika na stronę logowania?

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        cache: false,
        timeout: 30000,
        error: function(){
            return true;
        },
        success: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});
 255
Author: Peter Mortensen, 2009-04-16

9 answers

Jeśli nie chcesz, aby funkcja $.ajax() wróciła natychmiast, ustaw opcję async na false:

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        async: false,
        cache: false,
        timeout: 30000,
        fail: function(){
            return true;
        },
        done: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});

Ale, chciałbym zauważyć, że byłoby to sprzeczne z punktu AJAX. Należy również obsługiwać odpowiedź w funkcjach fail i done. Funkcje te będą wywoływane tylko wtedy, gdy odpowiedź zostanie odebrana z serwera.

 374
Author: cgp,
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
2020-09-15 11:10:40

Nie używam $.ajax, ale funkcji $.post i $.get, więc jeśli muszę czekać na odpowiedź, używam tego:

$.ajaxSetup({async: false});
$.get("...");
 43
Author: MilMike,
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-11-24 00:17:08

Podstawowy obiekt XMLHttpRequest (używany przez jQuery do wykonania żądania) obsługuje właściwość asynchroniczna. Ustaw na false . Jak

async: false
 35
Author: idrosid,
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
2009-04-16 12:33:09

Zamiast ustawiać async na false, co jest zwykle złym projektem, warto rozważyć zablokowanie interfejsu użytkownika, gdy operacja jest w toku.

Można to ładnie osiągnąć dzięki obietnicom jQuery w następujący sposób:

// same as $.ajax but settings can have a maskUI property
// if settings.maskUI==true, the UI will be blocked while ajax in progress
// if settings.maskUI is other than true, it's value will be used as the color value while bloking (i.e settings.maskUI='rgba(176,176,176,0.7)'
// in addition an hourglass is displayed while ajax in progress
function ajaxMaskUI(settings) {
    function maskPageOn(color) { // color can be ie. 'rgba(176,176,176,0.7)' or 'transparent'
        var div = $('#maskPageDiv');
        if (div.length === 0) {
            $(document.body).append('<div id="maskPageDiv" style="position:fixed;width:100%;height:100%;left:0;top:0;display:none"></div>'); // create it
            div = $('#maskPageDiv');
        }
        if (div.length !== 0) {
            div[0].style.zIndex = 2147483647;
            div[0].style.backgroundColor=color;
            div[0].style.display = 'inline';
        }
    }
    function maskPageOff() {
        var div = $('#maskPageDiv');
        if (div.length !== 0) {
            div[0].style.display = 'none';
            div[0].style.zIndex = 'auto';
        }
    }
    function hourglassOn() {
        if ($('style:contains("html.hourGlass")').length < 1) $('<style>').text('html.hourGlass, html.hourGlass * { cursor: wait !important; }').appendTo('head');
        $('html').addClass('hourGlass');
    }
    function hourglassOff() {
        $('html').removeClass('hourGlass');
    }

    if (settings.maskUI===true) settings.maskUI='transparent';

    if (!!settings.maskUI) {
        maskPageOn(settings.maskUI);
        hourglassOn();
    }

    var dfd = new $.Deferred();
    $.ajax(settings)
        .fail(function(jqXHR, textStatus, errorThrown) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.reject(jqXHR, textStatus, errorThrown);
        }).done(function(data, textStatus, jqXHR) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.resolve(data, textStatus, jqXHR);
        });

    return dfd.promise();
}

Z tym możesz teraz zrobić:

ajaxMaskUI({
    url: url,
    maskUI: true // or try for example 'rgba(176,176,176,0.7)'
}).fail(function (jqXHR, textStatus, errorThrown) {
    console.log('error ' + textStatus);
}).done(function (data, textStatus, jqXHR) {
    console.log('success ' + JSON.stringify(data));
});

I interfejs użytkownika zostanie zablokowany, dopóki Komenda ajax nie zwróci

Zobacz jsfiddle

 25
Author: kofifus,
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-09-28 14:22:51

Myślę, że byłoby łatwiej, gdybyś kodował swoją funkcję success, aby załadować odpowiednią stronę zamiast zwracać true lub false.

Na przykład zamiast zwracać true można zrobić:

window.location="appropriate page";

W ten sposób, gdy funkcja success zostanie wywołana, strona zostanie przekierowana.

 11
Author: samuelagm,
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-11-08 12:01:34

W nowoczesnym JS możesz po prostu użyć async/await, like:

  async function upload() {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: $(this).attr('href'),
            type: 'GET',
            timeout: 30000,
            success: (response) => {
                resolve(response);
            },
            error: (response) => {
                reject(response);
            }
        })
    })
}

Następnie wywołaj go w async funkcji jak:

let response = await upload();
 5
Author: Taohidul Islam,
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
2020-01-25 18:49:42

Ponieważ nie widzę tego tutaj, pomyślałem, że zwrócę również uwagę, że instrukcja jQuery when może być bardzo przydatna w tym celu.

Ich przykład wygląda tak:

$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {
  alert( jqXHR.status ); // Alerts 200
});

Część "then" zostanie wykonana dopiero po zakończeniu części" when".

 3
Author: Frank Hoffman,
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
2020-05-04 16:01:29

Powinno poczekać, aż żądanie zostanie zakończone. Następnie zwrócę get request body, z którego wywołana jest funkcja.

function foo() {
    var jqXHR = $.ajax({
        url: url,
        type: 'GET',
        async: false,
    });
    return JSON.parse(jqXHR.responseText);  
}
 1
Author: Hassan Ejaz,
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
2020-06-16 19:24:35

Ponieważ async ajax jest przestarzały, spróbuj użyć zagnieżdżonych funkcji asynchronicznych z obietnicą. Mogą wystąpić błędy składniowe.


async function fetch_my_data(_url, _dat) {

   async function promised_fetch(_url, _dat) {

      return new Promise((resolve, reject) => {
         $.ajax({
            url:  _url,
            data: _dat,
            type: 'POST',
            success: (response) => {
               resolve(JSON.parse(response));
            },
            error: (response) => {
               reject(response);
            }
         });
      });
   }

   var _data = await promised_fetch(_url, _dat);
   
   return _data;
}

var _my_data = fetch_my_data('server.php', 'get_my_data=1');

 1
Author: user7793758,
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
2020-07-10 20:26:25