12

我希望浏览器保持页面打开,直到发送 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。

谢谢,-马克斯

4

2 回答 2

13

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

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

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

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

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

更多关于询问用户是否在此处此处取消关闭事件。


旧答案

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

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

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

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

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

于 2010-06-04T00:44:53.610 回答
4

简而言之,您不能(也不应该)这样做。如果用户关闭浏览器,它正在关闭……没有unload样式事件可以保证完成,并且涉及延迟的 AJAX 操作不可能完成。

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

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

于 2010-06-04T00:43:48.150 回答