javascript 防止 Web 浏览器关闭,直到返回 AJAX 响应

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8743119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 04:26:36  来源:igfitidea点击:

Preventing web browser from closing until AJAX response is returned

javascriptjquerybrowser

提问by csdev86

I've got a game that runs in the web browser (as a plugin) and what I'm trying to do is:

我有一个在网络浏览器中运行的游戏(作为插件),我想要做的是:

  1. Detect if the user has decided to close the browser (Alt+F4, hitting the 'X' button etc)

  2. Prevent the browser from closing whilst we fire a call to our web services to log that the user has closed the browser

  3. Once we receive the response from the web services, release the lock and allow the browser to close as requested.

  1. 检测用户是否决定关闭浏览器(Alt+F4,点击“X”按钮等)

  2. 当我们调用 Web 服务以记录用户已关闭浏览器时,防止浏览器关闭

  3. 一旦我们收到来自 Web 服务的响应,就释放锁定并允许浏览器根据请求关闭。

The main reason we want to do this is we're having some concurrency problems and going through our logs we want to isolate people logging out / closing the browser from genuine instances where the plugin has crashed.

我们想要这样做的主要原因是我们遇到了一些并发问题,并且通过我们的日志,我们希望将退出/关闭浏览器的人与插件崩溃的真实实例隔离开来。

I looked into doing this with JQuery (for X-Browser compatability - Opera won't work but we don't have any users on Opera anyway thankfully):

我考虑用 JQuery 来做这件事(为了 X-Browser 兼容性 - Opera 无法工作,但幸运的是我们在 Opera 上没有任何用户):

$(window).bind('beforeunload', function(e) {
    e.preventDefault();
    // make AJAX call
});

The problem is that this displays a confirmation dialog to the user ('Are you sure you want to leave this page') which the user might confirm before the AJAX call is sent.

问题是这会向用户显示一个确认对话框(“您确定要离开此页面吗”),用户可能会在发送 AJAX 调用之前确认该对话框。

So the question is, is there a way of preventing the browser from closing until the response is received? Also 'beforeunload' fires when the page is changed as well - is there a way of distinguishing clicking on a link from actually clicking close?

所以问题是,有没有办法阻止浏览器在收到响应之前关闭?当页面更改时也会触发“beforeunload” - 有没有办法区分点击链接和实际点击关闭?

Grateful for any help wrt to this!

感谢您对此的任何帮助!

采纳答案by jAndy

Its tricky business to avoid the browser window from beeing closed. Actually, there is no way to do that, beside returning a non-undefinedvalue from the onbeforeunloadevent, like you described.

避免浏览器窗口被关闭是一项棘手的工作。实际上,除了像您描述的那样undefinedonbeforeunload事件中返回一个非值之外,没有办法做到这一点。

There is one possible suggestion I can make, that is creating a synchronizedajax request within the onbeforeunloadevent. For instance

我可以提出一个可能的建议,那就是在事件中创建一个同步的ajax 请求onbeforeunload。例如

window.onbeforeunload = function() {
    $.ajax({
        url: '/foo',
        type: 'GET',
        async: false,
        timeout: 4000
    });
};

In theory, this will block the browser for a maximum of 4 seconds. In reality, browsers will treat this differently. For instance, Firefox (I tested it on 9), will indeed not close the window immediately, but it also does not respect the timeout value there. I guess there is an internal maximum of like 2 seconds before the request is canceled and the window/tab gets closed. However, that should be enough in most cases I guess.

理论上,这将阻止浏览器最多 4 秒。实际上,浏览器会对此有所不同。例如,Firefox(我在 9 上测试过)确实不会立即关闭窗口,但它也不尊重那里的超时值。我猜在取消请求和关闭窗口/选项卡之前有一个内部最大值大约 2 秒。但是,我想在大多数情况下这应该足够了。

Your other question (how to distinguish between clicking a link), is fairly simple. As described above, onbeforeunloadlooks what is getting returned from its event handlers. So lets assume we have a variable which is globalfor our application, we could do something like

您的另一个问题(如何区分单击链接)相当简单。如上所述,onbeforeunload查看从其事件处理程序返回的内容。所以让我们假设我们有一个对我们的应用程序来说是全局的变量,我们可以做类似的事情

var globalIndicator = true;

// ... lots of code

window.onbeforeunload = function() {
    return globalIndicator;
};

At this point, we would always receive a confirmation dialog when the window/tab is about to get closed. If we want to avoid that for any anchor-click, we could patch it like

此时,当窗口/选项卡即将关闭时,我们总是会收到一个确认对话框。如果我们想避免任何锚点点击,我们可以像这样修补它

$( 'a[href^=http]' ).on('click', function() {
    globalIndicator = undefined;
});

回答by NobRuked

As for the first part of your question, there is no reliable way of preventing the browser from closing other than using window.onbeforeunload. The browser is there to serve the user and if the user chooses to close his browser then it will do so.

至于您问题的第一部分,除了使用window.onbeforeunload. 浏览器是为用户服务的,如果用户选择关闭他的浏览器,它就会这样做。

For your second question, it is reasonably easy to distinguish a click on a link from other events triggering an onbeforeunloadevent by jQuery:

对于您的第二个问题,将链接上的点击与onbeforeunloadjQuery触发事件的其他事件区分开来是相当容易的:

$('a').click(function(e) {...});

You could use this, for example, to make sure a click will not trigger unbeforeunload:

例如,您可以使用它来确保点击不会触发unbeforeunload

$('a').click(function(e) {window.onbeforeunload = null});

回答by Pradeep Yadav

You can use below code to prevent the browser from getting closed:-

您可以使用以下代码来防止浏览器关闭:-

window.onbeforeunload = function() {

//Your code goes here.

    return "";
} 

Now when user closes the browser then he gets the confirmation dialogue because of return ""; & waits for user's confirmation & this waiting time makes the request to reach the server.

现在,当用户关闭浏览器时,由于返回“”,他会收到确认对话框;& 等待用户的确认 & 这个等待时间使请求到达服务器。

回答by tinyd

I'm pretty sure that what you want isn't possible using JavaScript. But since you have a browser plugin, shouldn't you be able to check whether your plugin object was cleaned up correctly? I'm not sure if you're using ActiveX, NPAPI or something like Firebreath, but these frameworks all have lifecycle methods that will be called on your plugin in the event of a normal shutdown, so you should be able to write something to the logs at this point. If the plugin crashes, these won't be called.

我很确定您想要的东西使用 JavaScript 是不可能的。但是既然你有一个浏览器插件,难道你不应该能够检查你的插件对象是否被正确清理了吗?我不确定您使用的是 ActiveX、NPAPI 还是 Firebreath 之类的东西,但是这些框架都有生命周期方法,在正常关闭的情况下会在您的插件上调用这些方法,因此您应该能够向记录此时。如果插件崩溃,这些将不会被调用。