如何使jQuery在返回之前等待Ajax调用完成?

How do I make jQuery wait for an Ajax call to finish before it returns?

我有一个服务器端功能,需要登录。如果用户登录,函数将在成功时返回1。否则,函数将返回登录页面。

我想使用ajax和jquery调用函数。我要做的是用一个普通的链接提交请求,并在其上应用一个单击功能。如果用户未登录或函数失败,我希望Ajax调用返回true,以便href触发。

但是,当我使用以下代码时,函数在Ajax调用完成之前退出。

如何将用户优雅地重定向到登录页?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$(".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;
            }
        }
    });
});


如果不希望$.ajax()功能立即返回,请将async选项设置为false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$(".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的观点相反。另外,您应该在errorsuccess函数中处理响应。只有从服务器收到响应时,才会调用这些函数。


我使用的不是$.ajax,而是$.post$.get函数,因此如果我需要等待响应,我使用这个:

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


基础的xmlhttpRequest对象(jquery用于发出请求)支持异步属性。设置为假。喜欢

1
async: false

您可以考虑在操作挂起时阻止UI,而不是将async设置为false(这通常是错误的设计)。

这可以通过jquery承诺很好地实现,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 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(''); // 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();
}

有了这个,你现在可以做:

1
2
3
4
5
6
7
8
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));
});

用户界面将一直阻塞,直到Ajax命令返回

参见JSFIDLE


我认为,如果编写success函数代码来加载适当的页面,而不是返回truefalse,事情会更容易一些。

例如,您可以这样做,而不是返回true

1
window.location="appropriate page";

这样,当调用success函数时,页面就会被重定向。