我如何让jQuery等待Ajax调用完成再返回?


243

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

我想使用Ajax和jQuery调用该函数。我要做的是使用普通链接提交请求,并应用点击功能。如果用户未登录或功能失败,则我希望Ajax调用返回true,以便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设置为false是一个错误的设计,并且“不会处理超时等”。可能是尝试这种简化的解决方案- stackoverflow.com/a/11576418/6937841

Answers:


355

如果您不希望$.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的观点背道而驰。另外,您应该在errorsuccess函数中处理响应。仅当从服务器收到响应时,才调用这些功能。


10
在我看来,传递良好的实践并不是判断,这是StackOverflow上一些最佳答案的标志。
semperos 2011年

68
永远不要使用async: false等待不可靠的网络I / O时,浏览器的事件循环将挂起。总有更好的方法。在这种情况下,链接的目标可以验证用户会话,并验证到登录页面的302。
马修

3
对于测试,async: false可能非常有用。
耶勒(Jarrett)2013年

4
@马修真的吗?在将用户发送到其他页面或刷新之前,使用异步发送ajax的替代方法是什么?
NoBugs 2014年

2
asyncfalse在大多数浏览器用例中,不建议使用value值。在较新版本的浏览器中可能会引发异常。请参阅xhr.spec.whatwg.org/#sync-warning(适用于使用jQuery async的xhr open方法的参数)。
弗雷德里克

42

我不使用$.ajax,但$.post$.get功能,所以如果我需要等待响应,我用这个:

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

34

底层XMLHttpRequest对象(由jQuery使用以发出请求)支持异步属性。将其设置为false。喜欢

async: false

24

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

使用jQuery promise可以很好地实现这一点,如下所示:

// 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


除了单行代码,将async设置为false不会完全相同吗?
文森特

4
一点也不。将async设置为false会使请求异步-这将暂停处理直到返回,这通常是不好的做法,例如将不处理任何事件,其他ajax请求,超时等。您还可以修改上面的代码,以在处理ajax时仅阻止部分UI(即它将影响的部分)
kofifus 2015年

11

我认为,如果您对success函数进行编码以加载适当的页面而不是返回trueor,事情将会变得更加容易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

您能详细说明一下吗?测试代码后,我已经回答了这个问题,它应该可以工作。
Taohidul Islam

await不能在异步函数之外使用,它会引发错误。
ppetree

是的,我在答案的第二行中提到了“然后在async函数中调用它”。
Taohidul Islam

这是一个很好的解决方案,但是要帮助其他人寻找一个好的解决方案(就像我以前一样),您应该编辑代码并以更完整的方式显示它。也许甚至包括一个小提琴的链接。那将是真棒!
ppetree

0

因为我在这里没有看到它,所以我想我也要指出jQuery when语句对于此目的非常有用。

他们的示例如下所示:

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

“那时”部分要等到“时间”部分完成后才能执行。


0

它应该等到获取请求完成。之后,我将从调用函数的地方返回get请求主体。

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

请说明您的解决方案。
退学

添加了@Dropout。
Hassan Ejaz

感谢@Hassan Ejaz!没有解释并且仅是代码的答案被标记为省力。
辍学
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.