Як змусити jQuery чекати завершення дзвінка Ajax, перш ніж він повернеться?


244

У мене є серверна функція, яка вимагає входу. Якщо користувач увійшов у систему, функція поверне успіх 1. Якщо ні, функція поверне сторінку входу.

Я хочу викликати функцію за допомогою Ajax та jQuery. Те, що я роблю, - це подати запит зі звичайного посилання, на якому застосовано функцію клацання. Якщо користувач не входить у систему або функція не працює, я хочу, щоб Ajax-виклик повернувся істинним, щоб запустити href.

Однак, коли я використовую наступний код, функція закінчується перед тим, як виконати виклик Ajax.

Як я можу вишукано перенаправити користувача на сторінку входу?

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

2
Це може бути старий потік, але, як @kofifus зазначає, налаштування async to false - це поганий дизайн, і "жодних тайм-аутів тощо не буде оброблено". Можна спробувати це спрощене рішення - stackoverflow.com/a/11576418/6937841
Shan

Відповіді:


357

Якщо ви не хочете, щоб $.ajax()функція поверталася негайно, встановіть asyncопцію false:

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

Але, зауважу, це суперечить точці AJAX. Крім того, вам слід обробляти відповідь у функціях errorта success. Ці функції будуть викликатися лише тоді, коли відповідь надійде від сервера.


10
Передача належних практик, на мою думку, не судить, і це знак найкращих відповідей тут на StackOverflow.
semperos

68
Ніколи не використовуйте async: false. Цикл подій браузера буде висіти під час очікування ненадійного мережевого вводу-виводу. Завжди є кращий спосіб. У цьому випадку ціль посилання може підтвердити сеанс користувача та 302 на сторінці входу.
Матвій

3
Для тестування async: falseможе бути дуже корисним.
Джарретт

4
@Matthew Дійсно? Яка альтернатива надсиланню ajax з async перед відправкою користувача на іншу сторінку або оновленням?
NoBugs

2
asyncfalseу більшості випадків використання браузера значення має застаріле. Він може кидати винятки в новіших версіях браузерів. Див. Xhr.spec.whatwg.org/#sync-warning (застосовується до asyncпараметра openметоду xhr , для чого використовується jQuery).
Фредерік

42

Я не використовую , $.ajaxале в $.postі $.getфункції, тому якщо мені потрібно чекати відповіді, я використовую це:

$.ajaxSetup({async: false});
$.get("...");

34

Базовий об'єкт XMLHttpRequest (який використовується jQuery для подання запиту) підтримує асинхронне властивість. Встановіть значення false . Подібно до

async: false

24

Замість того, щоб встановити асинхронізацію на хибну, що зазвичай є поганим дизайном, ви можете розглянути можливість блокування інтерфейсу користувача, поки операція не завершена.

Це можна добре досягти за допомогою jQuery обіцянок таким чином:

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

з цим тепер можна зробити:

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

І UI буде блокувати, поки команда ajax не повернеться

див. jsfiddle


Чи не встановлення функції асинхронізації на помилку робить те саме, крім одного рядка коду?
Вінсент

4
Зовсім ні. Якщо встановити асинхронізування на помилковому, зробити запит асинхронним - це зупинка обробки, поки вона не повернеться, що, як правило, є поганою практикою, наприклад, жодні події, інші запити ajax, тайм-аути тощо не будуть оброблені. Ви також можете змінити код вище, щоб заблокувати лише частину інтерфейсу користувача, поки ваш ajax обробляє (тобто частину, на яку це вплине)
kofifus

11

Я думаю, що все буде простіше, якщо ви кодуєте свою successфункцію для завантаження відповідної сторінки, а не повернення trueабо false.

Наприклад, замість повернення trueви можете зробити:

window.location="appropriate page";

Таким чином, коли функція успіху називається, сторінка перенаправляється.


5

У сучасному JS ви можете просто використовувати async/ await, як:

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

Потім викликайте його у такій asyncфункції, як:

let response = await upload();

1
Ваш код не буде працювати ... ви на правильному шляху, але як є, він не працюватиме.
ppetree

Чи можете ви, будь ласка, детальніше розробити? Після тестування коду я відповів на це питання, він повинен працювати.
Таохідул Іслам

wait не може бути використаний поза функцією асинхронізації, вона видає помилку.
ppetree

Так, я згадав про це у другому останньому рядку своєї відповіді: "Тоді викликайте це у asyncфункції".
Таохідул Іслам

Це чудове рішення, але щоб допомогти іншим, хто шукає чудове рішення (як я), слід відредагувати свій код і показати його більш повно. Можливо, навіть включити посилання на загадку. Це було б чудово!
ppetree

0

Оскільки я не бачу його згадуваного тут, я подумав, що я також зазначу, що jQuery, коли оператор може бути дуже корисним для цієї мети.

Їх приклад виглядає приблизно так:

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

Частина "тоді" не буде виконана, поки частина "коли" не закінчиться.


0

Слід зачекати, поки отримати запит. Після цього я повернусь отримати тіло запиту, звідки викликається функція.

function foo() {
    var jqXHR = $.ajax({
        url: url,
        type: 'GET',
        async: false,
    });
    return JSON.parse(jqXHR.responseText);  
}

Будь ласка, поясніть своє рішення.
Випадання

1
Додано @Dropout.
Хасан Еяз

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