Bagaimana cara membuat jQuery menunggu panggilan Ajax selesai sebelum kembali?

244

Saya memiliki fungsi sisi server yang memerlukan login. Jika pengguna masuk fungsi akan mengembalikan 1 pada keberhasilan. Jika tidak, fungsi akan mengembalikan halaman login.

Saya ingin memanggil fungsi menggunakan Ajax dan jQuery. Apa yang saya lakukan adalah mengirimkan permintaan dengan tautan biasa, dengan fungsi klik diterapkan di sana. Jika pengguna tidak masuk atau fungsi gagal, saya ingin panggilan Ajax kembali benar, sehingga href memicu.

Namun, ketika saya menggunakan kode berikut, fungsi keluar sebelum panggilan Ajax selesai.

Bagaimana saya bisa mengarahkan pengguna dengan anggun ke halaman login?

$(".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;
            }
        }
    });
});
Hobhouse
sumber
2
Mungkin utas lama, tetapi seperti @kofifus menunjukkan pengaturan async ke false adalah desain yang buruk dan "tidak ada waktu habis, dll akan diproses". Mungkin akan coba solusi yang disederhanakan ini - stackoverflow.com/a/11576418/6937841
Shan

Jawaban:

357

Jika Anda tidak ingin $.ajax()fungsi kembali dengan segera, atur asyncopsi ke 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;
            }
        }
    });
});

Tapi, saya akan mencatat bahwa ini akan bertentangan dengan titik AJAX. Selain itu, Anda harus menangani respons dalam errordan successfungsi. Fungsi-fungsi itu hanya akan dipanggil ketika respons diterima dari server.

cgp
sumber
10
Melewati praktik yang baik, menurut saya, tidak menilai, dan merupakan tanda dari beberapa jawaban terbaik di sini di StackOverflow.
semperos
68
Jangan pernah gunakan async: false. Perulangan acara browser akan hang saat menunggu di I / O jaringan yang tidak dapat diandalkan. Selalu ada cara yang lebih baik. Dalam hal ini, target tautan dapat memverifikasi sesi pengguna dan 302 ke halaman login.
Matius
3
Untuk pengujian, async: falsebisa sangat bermanfaat.
Jarrett
4
@ Matius Benarkah? Apa alternatif untuk mengirim ajax dengan async sebelum mengirim pengguna ke halaman lain atau menyegarkan?
NoBugs
2
asyncdengan nilai falsesudah usang dalam sebagian besar kasus penggunaan browser. Itu bisa melempar pengecualian di versi browser yang lebih baru. Lihat xhr.spec.whatwg.org/#sync-warning (berlaku untuk asyncparameter openmetode xhr , yang menggunakan jQuery).
Frédéric
42

Saya tidak menggunakan $.ajaxtetapi fungsi $.postdan $.get, jadi jika saya harus menunggu jawaban, saya menggunakan ini:

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

Objek XMLHttpRequest yang mendasarinya (digunakan oleh jQuery untuk mengajukan permintaan) mendukung properti asinkron. Setel ke false . Suka

async: false
idrosid
sumber
24

Alih-alih mengatur async ke false yang biasanya merupakan desain yang buruk, Anda mungkin ingin mempertimbangkan untuk memblokir UI saat operasi menunggu.

Ini dapat dicapai dengan baik dengan janji-janji jQuery sebagai berikut:

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

dengan ini sekarang Anda dapat melakukan:

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

Dan UI akan memblokir sampai perintah ajax kembali

lihat jsfiddle

kofifus
sumber
Tidak menetapkan async ke false melakukan hal yang sama persis kecuali dalam satu baris kode?
Vincent
4
Tidak semuanya. Pengaturan async ke false membuat permintaan async - yaitu menghentikan pemrosesan sampai kembali yang biasanya merupakan praktik buruk, misalnya tidak ada acara, permintaan ajax lainnya, waktu tunggu dll akan diproses. Anda juga dapat memodifikasi kode di atas untuk memblokir hanya sebagian dari UI saat ajax Anda sedang memproses (yaitu bagian yang akan
terpengaruh
11

Saya pikir semuanya akan lebih mudah jika Anda memberi kode successfungsi Anda untuk memuat halaman yang sesuai daripada mengembalikan trueatau false.

Misalnya, alih-alih kembali, trueAnda dapat melakukan:

window.location="appropriate page";

Dengan begitu ketika fungsi sukses disebut halaman akan dialihkan.

samuelagm
sumber
5

Di JS modern Anda cukup menggunakan async/ await, seperti:

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

Kemudian menyebutnya dalam suatu asyncfungsi seperti:

let response = await upload();
Islam Taohidul
sumber
1
Kode Anda tidak akan berfungsi ... Anda berada di jalur yang benar tetapi seperti itu, itu tidak akan berfungsi.
ppetree
Bisakah Anda menjelaskan lebih lanjut? Setelah menguji kode saya sudah menjawab pertanyaan ini, itu harus bekerja.
Taohidul Islam
menunggu tidak dapat digunakan di luar fungsi async, ia melempar kesalahan.
ppetree
Ya, saya sudah menyebutkannya di baris kedua dari jawaban saya, "Kalau begitu sebut saja dalam suatu asyncfungsi".
Taohidul Islam
Ini solusi hebat tetapi untuk membantu orang lain mencari solusi hebat (seperti saya sebelumnya), Anda harus mengedit kode Anda dan menunjukkannya dengan cara yang lebih lengkap. Mungkin bahkan menyertakan tautan ke biola. Itu akan luar biasa!
ppetree
0

Karena saya tidak melihatnya disebutkan di sini saya pikir saya juga akan menunjukkan bahwa jQuery kapan bisa sangat berguna untuk tujuan ini.

Contoh mereka terlihat seperti ini:

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

Bagian "then" tidak akan dieksekusi sampai bagian "kapan" selesai.

Frank Hoffman
sumber
0

Itu harus menunggu sampai permintaan selesai. Setelah itu saya akan kembali mendapatkan request body dari mana fungsi dipanggil.

function foo() {
    var jqXHR = $.ajax({
        url: url,
        type: 'GET',
        async: false,
    });
    return JSON.parse(jqXHR.responseText);  
}
Hassan Ejaz
sumber
Tolong jelaskan solusi Anda.
Putus sekolah
1
Menambahkan @Dropout.
Hassan Ejaz
Terima kasih @Hassan Ejaz! Jawaban yang tidak memiliki penjelasan dan hanya kode yang ditandai sebagai upaya rendah.
Putus sekolah