ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个需要登录的服务器端功能。如果用户已登录,该函数将在成功时返回 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;
            }
        }
    });
});
可能是一个旧线程,但正如@kofifus 指出的那样,将 async 设置为 false 是一个糟糕的设计,并且“不会处理任何超时等”。可能会尝试这个简化的解决方案 - stackoverflow.com/a/11576418/6937841
您可以将 return true; 更改为 window.location.href = url;,一旦 ajax 调用完成,它将优雅地重定向到登录页面。

m
mmv_sat

如果您不希望 $.ajax() 函数立即返回,请将 async 选项设置为 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;
            }
        }
    });
});

但是,我会注意到这与 AJAX 的观点背道而驰。此外,您应该在 faildone 函数中处理响应。只有在从服务器收到响应时才会调用这些函数。


在我看来,传递良好实践并不是评判,而是 StackOverflow 上一些最佳答案的标志。
永远不要使用 async: false 浏览器的事件循环将在等待不可靠的网络 I/O 时挂起。总有更好的方法。在这种情况下,链接的目标可以验证用户会话和 302 到登录页面。
对于测试,async: false 可能非常有用。
@马修真的吗?在将用户发送到其他页面或刷新之前发送带有异步的 ajax 的替代方法是什么?
在大多数浏览器用例中,不推荐使用值为 falseasync。它可能会在较新版本的浏览器中引发异常。请参阅 xhr.spec.whatwg.org/#sync-warning(适用于 xhr open 方法的 async 参数,该方法使用 jQuery)。
f
fragilewindows

我没有使用 $.ajax 而是使用 $.post$.get 函数,所以如果我需要等待响应,我使用这个:

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

i
idrosid

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

async: false

d
doydoy44

与其将 async 设置为 false(这通常是糟糕的设计),不如考虑在操作挂起时阻止 UI。

这可以通过 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 不会做完全相同的事情吗?
一点也不。将 async 设置为 false 会使请求异步 - 即暂停处理直到它返回,这通常是不好的做法,例如不会处理任何事件、其他 ajax 请求、超时等。您还可以修改上面的代码以在处理 ajax 时仅阻止部分 UI(即它将影响的部分)
A
Anthony Grist

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

例如,您可以执行以下操作,而不是返回 true

window.location="appropriate page";

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


这是问题的真正答案。
T
Taohidul Islam

在现代 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();

您的代码将无法工作......您在正确的轨道上,但实际上,它不会工作。
你能详细说明一下吗?在测试了我已经回答了这个问题的代码之后,它应该可以工作。
await 不能在 async 函数之外使用,它会引发错误。
是的,我在答案的倒数第二行中提到了它,“然后在 async 函数中调用它”。
这是一个很好的解决方案,但为了帮助其他人寻找一个很好的解决方案(就像我一样),您应该编辑您的代码并以更完整的方式显示它。甚至可能包括指向小提琴的链接。那将是真棒!
F
Frank Hoffman

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

他们的示例如下所示:

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

在“when”部分完成之前,“then”部分不会执行。


u
user7793758

由于不推荐使用异步 ajax,因此请尝试使用带有 Promise 的嵌套异步函数。可能存在语法错误。


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


H
Hassan Ejaz

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

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

请解释您的解决方案。
添加了@Dropout。
谢谢@Hassan Ejaz!没有解释并且只是代码的答案被标记为低工作量。
S
Stu

最初的问题是在 12 年前的今天提出的,是“我如何让 jQuery 等待 Ajax 调用在它返回之前完成?”从那时起,jQuery 已经走过了漫长的道路。

上面提到了一些解决方案,但我无法让它们中的任何一个与最新版本的 jQuery 一起工作: $.when().then.() 似乎不是同步的,除非它使用 'async: false'不再支持,因此在较新版本的 jQuery 中不起作用。

但是承诺是内置在 jQuery ajax 调用中的,因此使 ajax 调用同步应该不难。

我使用命名空间的 js 函数,所以下面的例子就是这种格式。该示例用于自定义表单验证,它调用服务器来验证用户输入是否不会尝试复制现有项目。

除非使用 Babel,否则此代码可能无法在 IE 或 Legacy Edge 中运行,但我倾向于阻止这些浏览器,因为 Microsoft 不再支持它们。

///Namespace validate
check: async function(settings){
    let IsValid = false;
    let Message = ''
    let data = await validate.serverCheck('function', value);
    IsValid = data.OK;
    Message = data.Message;
}

serverCheck: async function (fn, value) {
    var request = {
        validateValue: $.sanitize(value)
    };

    let result;

    try {
            result = await $.ajax({
                dataType: "json",
                type: "post",
                url: "/api/validate/" + fn + "/",
                data: request
        });

        return result;
    } catch (x) {}
}

你有它