Javascript:等到ajax请求完成关闭页面[重复]

Posted

技术标签:

【中文标题】Javascript:等到ajax请求完成关闭页面[重复]【英文标题】:Javascript: wait until ajax request finishes to close page [duplicate] 【发布时间】:2011-02-27 14:03:16 【问题描述】:

我希望浏览器在发送 ajax 请求之前保持页面打开。这就是我想象中的样子

var requestsPending = 0;

window.onbeforeunload = function() 
    showPleaseWaitMessage();
    while(requestsPending > 0);


// called before making ajax request, atomic somehow
function ajaxStarted() 
    requestsPending++;

// called when ajax finishes, also atomic
function ajaxFinished() 
    requestsPending--;

不幸的是,JS 不做多线程。据我了解,回调 (ajaxFinished) 永远不会执行,因为浏览器会尝试等待 while 循环完成执行它,因此它将永远循环。

这样做的正确方法是什么?有没有办法强制 JS 评估其待办事项列表中的下一件事,然后返回到 while 循环?或者一些语法来“加入”一个ajax调用?我正在为我的 ajax 使用 DWR。

谢谢, -最大

【问题讨论】:

【参考方案1】:

编辑根据您在下面的评论,修改后的答案:

如果你想阻塞直到一个先前发起的请求完成,你可以这样做:

window.onbeforeunload = function(event) 
    var s;
    event = event || window.event;
    if (requestsPending > 0) 
        s = "Your most recent changes are still being saved. " +
            "If you close the window now, they may not be saved.";
        event.returnValue = s;
        return s;
    

然后,浏览器会提示用户询问他们是要离开页面还是留在页面上,让他们自行控制。如果他们停留在页面上并且在提示出现时请求已经完成,那么下次他们关闭页面时,它会让他们在不询问的情况下关闭它。

请注意,在现代浏览器上,您的消息将不会显示;相反,浏览器将使用通用消息。所以在现代浏览器上,返回任何非空白字符串就足够了。不过,您可能希望返回一个有用的字符串(例如上面的),以防您的用户使用仍然会显示它的过时浏览器。

更多关于询问用户是否取消关闭事件here和here。


旧答案

理想情况下,如果可能,您希望避免这样做。 :-)

如果无法避免,可以进行 Ajax 请求同步,这样它就会阻塞onbeforeunload 进程,直到它完成。我不知道 DWR,但我希望它有一个标志来控制请求是否同步。在原始 XmlHTTPRequest API 中,这是open 的第三个参数:

req.open('GET', 'http://www.mozilla.org/', false);
                                            ^ false = synchronous

大多数libraries 都会有一个等价物。例如,在Prototype 中,它是选项中的asynchronous: false 标志。

但同样,如果您可以避免在页面卸载过程中触发 Ajax 请求,我会的。在设置、传输和完成请求时会有明显的延迟。最好让服务器使用超时来关闭您尝试关闭的任何内容。 (这可能是一个相当短的超时时间;您可以通过在页面打开时定期在页面中使用 异步 Ajax 请求来保持会话处于活动状态 - 例如,每分钟一个,两分钟后超时。)

【讨论】:

即使你让它同步,浏览器也不会等待,至少不是所有的......所以它仍然不可靠(它应该是 IMO,我的浏览器不应挂起,因为 10 个选项卡中有 1 个想要发出一些我不关心的 AJAX 请求)。 @Nick:你说的是beforeunload,还是unload?因为在beforeunload 中,如果我愿意,我可以启动像alerts 这样具有侵入性的东西。我有一段时间没有这样做(在beforeunload 期间发送请求)(因为我认为这不是一个好主意),但是当我几年前这样做时,它在(我认为)IE6 中可靠地工作、IE7 和 Firefox ......嗯......无论 Firefox 几年前是最新的。 :-) @T.J.警报阻止了 UI 线程,它不是像 ajax 那样的回调,所以不同的球赛......像 OP 试图做的事情在任何一种情况下都不起作用(大多数时候),这是一场火灾并忘记......但即使是火部分是否完成取决于浏览器。 诀窍是,这些 ajax 调用是在用户关闭窗口之前启动的。例如,假设您有一个附有编辑链接的可重新排序的元素列表。如果用户重新排序列表,然后在 ajax 告诉服务器列表已重新排序之前单击链接,当浏览器转到编辑页面时,他会丢失更改。我想强制浏览器等到ajax调用完成后再离开页面。 @Nick:我得再试一次(现在不能)。但根据 OP 的评论,事实证明,这不是他想做的事! :-)【参考方案2】:

简而言之,您不能(也不应该)这样做。如果用户关闭浏览器,它就会关闭...没有unload 样式事件保证完成,而涉及延迟的 AJAX 操作更多不太可能完成。

您应该考虑在另一个时间点触发您的事件,或者完全改变方法,但是在 unload 事件中进行 AJAX 调用将是不可靠的,充其量

作为对上述不应该部分的补充,请这样想,在任何给定窗口上通常打开多少个选项卡?我通常打开 4-6 个 chrome 窗口,每个窗口有 5-12 个选项卡...我的浏览器窗口是否应该挂起,因为其中 1 个选项卡想要发出一些我不关心的 AJAX 请求?我不希望它作为一个用户,所以我不会尝试作为一个开发者来做它。这当然只是一个观点,但值得深思。

【讨论】:

那么什么是解决这个问题的好方法呢?例如,假设您有一个附加了编辑链接的可重新排序的元素列表。如果用户重新排序列表,然后在 ajax 告诉服务器列表已重新排序之前单击链接,当浏览器转到编辑页面时,他会丢失更改。 @maxdj - 一个 .live() 处理程序,例如,如果 ajax 请求正在进行,则返回 false,如果不是,则继续......任何阻止链接在不应该工作时工作的东西真的。

以上是关于Javascript:等到ajax请求完成关闭页面[重复]的主要内容,如果未能解决你的问题,请参考以下文章

不想等到服务器响应 AJAX 请求

AJAX初次接触

Ajax同步异步请求

Ajax 调用阻止其他 javascript 代码

Web 关闭页面时发送 Ajax 请求 —— sendBeacon

Ajax