Javascript:等待ajax请求完成关闭页面

发布于 2024-09-04 07:39:10 字数 603 浏览 3 评论 0 原文

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

谢谢, -最大限度

I would like the browser to keep the page open until the ajax requests are sent. This is what I imagine it would look like

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

Unfortunately, JS doesn't do multi-threading. To my understanding, the callback (ajaxFinished) would never be executed because the browser would try to wait until the while loop finishes to execute it, and so the it would loop forever.

What's the right way to do this? Is there maybe a way to force JS to evaluate the next thing in its to-do list and then come back to the while loop? Or some syntax to "join" with an ajax call? I'm using DWR for my ajax.

Thanks,
-Max

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

相思故 2024-09-11 07:39:10

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

如果您想阻止直到先前发起的请求完成,您可以这样做:

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

大多数库< /a> 将有一个等效的。例如,在 Prototype 中,它是选项中的 asynchronous: false 标志。

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

Edit Based on your comment below, a revised answer:

If you want to block until a previously-initiated request completes, you can do it like this:

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

The browser will then prompt the user to ask whether they want to leave the page or stay on it, putting them in control. If they stay on the page and the request has completed while the prompt was up, the next time they go to close the page, it'll let them close it without asking.

Note that on modern browsers, your message will not be shown; instead, the browser will use a generic message. So on modern browsers, returning any non-blank string is sufficient. Still, you may want to return a useful string (such as the above) in case your user is using an obsolete browser that will still show it.

More on asking the user whether to cancel close events here and here.


Old answer :

Ideally, if possible, you want to avoid doing this. :-)

If you can't avoid it, it's possible to make an Ajax request synchronous, so that it blocks the onbeforeunload process until it completes. I don't know DWR, but I expect it has a flag to control whether the request is synchronous or not. In the raw XmlHTTPRequest API, this is the third parameter to open:

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

Most libraries will have an equivalent. For instance, in Prototype, it's the asynchronous: false flag in the options.

But again, if you can possibly avoid firing off Ajax requests as part of the page unload, I would. There will be a noticeable delay while the request is set up, transmitted, and completed. Much better to have the server use a timeout to close down whatever it is that you're trying to close down with this. (It can be a fairly short timeout; you can keep the session alive by using asynchronous Ajax requests periodically in the page while it's open — say, one a minute, and time out after two minutes.)

零崎曲识 2024-09-11 07:39:10

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

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

作为上述“不应该”部分的附录,请这样想,您通常在任何给定窗口上打开多少个选项卡?我通常会打开 4-6 个 Chrome 窗口,每个窗口有 5-12 个选项卡...我的浏览器窗口是否应该因为其中 1 个选项卡想要发出一些我不关心的 AJAX 请求而挂起?我不希望它作为用户,所以我不会尝试以开发人员的身份来做这件事。这当然只是一个意见,但却值得深思。

In short, you cannot (and shouldn't) do this. If a user closes the browser, it's closing...no unload style events are guaranteed to finish, and something doing AJAX with involves latency is more unlikely to finish.

You should look at firing your events at another point, or change the approach altogether, but making an AJAX call in an unload event is going to unreliable, at best.

As an addendum to the above on the shouldn't part, think about it this way, how many tabs do you usually have open on any given window? I typically have 4-6 chrome windows open with 5-12 tabs each...should my browser window hang open because 1 of those tabs wants to make some AJAX request I don't care about? I wouldn't want it to as a user, so I wouldn't try and do it as a developer. This is just an opinion of course, but food for thought.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文