Skip to content

Chrome 中使用 onbeforeunload 来提示离开页面时数据是否已保存

🏷️ Chrome

最简单的写法如下,效果是只要用户在当前页面有任何动作,在页面离开时都会显示确认框。

注意

这里返回的字符串原本是自定义的确认框消息,但现在已经不再支持了,仅显示浏览器默认的提示信息。

javascript
$(window).on('beforeunload', function (event) {
    return '有修改未保存!请确认是否离开?';
});

当然也可以自定义标志位来控制是否显示确认框。示例如下:

javascript
$(window).on('beforeunload', function (event) {
    if (isChanged) {
        return '有修改未保存!请确认是否离开?';
    }
});

Chrome 关于 onbeforeunload 的改动。

Chrome 51Custom messages in onbeforeunload dialogs (removed)

通过 onbeforeunload 方法自定义的确认消息被改成了默认的通用消息,也就是说 onbeforeunload 方法随便返回一个字符串就可以了。
实际测试发现除了 return undefined;return; 不行之外,return null;return ""; 都可以显示确认框。

Custom messages in onbeforeunload dialogs (removed)

A window’s onbeforeunload property may be set to a function that returns a string. If the function returns a string, then before unloading the page, a dialog is shown to have the user confirm that they indeed want to navigate away.

The string provided by the function will no longer be shown in the dialog. Rather, a generic string not under the control of the webpage will be shown.

Chrome 52Pause event loop during modal dialogs

阻止了对话框系显示时的事件循环。

Pause event loop during modal dialogs

When using alert(), confirm() or onbeforeunload, Chromium's old behavior was to block JS waiting for the result, but allows all declarative animations to continue. This change is to make all main-thread tasks (such as <marquee> and CSS 2d animations) also pause during this interval.

Comments

Chrome’s old behavior was implemented with a nested message loop on the Blink main thread. Any code that might ever run on a nested message loop must be robust to reentrancy and reordering, otherwise there will be stability and security bugs.

Chrome 60Require user gesture for beforeunload dialogs

只有在用户行为触发时才会显示对话框。

Require user gesture for beforeunload dialogs

The beforeunload dialog will only be shown if the frame attempting to display it has received a user gesture or user interaction (or if any embedded frame has received such a gesture). (There will be no change to the dispatch of the beforeunload event, just a change to whether the dialog is shown.)

Chrome 78 : Disallow sync XHR in page dismissal

禁用了 同步的 XHR。
这个改动当前(2019-09-30)还处于 Beta 状态。

Disallow sync XHR in page dismissal

Chrome now disallows synchronous XHR during page dismissal when the page is being navigated away from or closed by the user. This involves the following events (when fired on the path of page dismissal): beforeunload, unload, pagehide, and visibilitychange.

Synchronous XHR is on the deprecation path. It hurts the end user experience.
beforeunload and unload are used by third parties and first parties to send analytics data to servers. While this is reasonable, there are no good reasons to use synchronous XHR. Instead SendBeacon, Fetch keep-alive should be used (in addition to sending analytics periodically and on pagevisibility etc.).

Page dismissal is also an interesting scenario for the following reasons:

  1. It hurts the user experience when the user is trying to leave the page or navigate (up to a max timeout of 1s, which is 2s in practice in chrome)

  2. The intention of beforeunload handler is a mechanism for preventing data loss for users, however it is used by third parties as a way to reliably do a bunch of work (including sync xhr), up to the max timeout. Some relevant data in this slide deck. This hurts the end user experience.

  3. As part of Page Lifecycle API: we want to experiment with running the beforeunload handler at the time of freezing (to determine risk of data loss) to support proactive tab discarding. And Sync XHR (and large amount of work) is problematic here.

For now, enterprise users can use the AllowSyncXHRInPageDismissal policy flag to allow synchronous XHR requests during page unload. We expect to remove this flag in Chrome 82.