使用beforeunload事件有哪些限制?

20

beforeunload回调函数中可以做什么和不能做什么?

是否可以打开XHR/fetch并向服务器发送数据? 如果不行,是否可以只发送数据,并且没有任何成功回调会阻塞?

是否可以使用window.location更改页面的位置? 该函数执行多长时间?

window.addEventListener("beforeunload", function (event) {
    // code
});

1
如果函数是同步的,它应该总是执行到结束。 - Bergi
1
你做了哪些研究? - Bergi
2个回答

45

在“beforeunload”回调中,您可以放置任何想要的内容,但是除非使用同步/阻塞代码,否则不能保证它将被执行。

这里是一个用于演示目的的阻塞睡眠函数:

function sleep(delay) {
  var start = new Date().getTime();
  while (new Date().getTime() < start + delay);
}

任何同步、阻塞的代码都保证会完整地执行:

window.addEventListener("beforeunload", function (event) {
  console.log("Blocking for 1 second...");
  sleep(1000);
  console.log("Done!!");
});

任何异步代码(即带有回调函数的代码)都将在事件循环队列中排队,但根据您的浏览器何时完成“卸载”操作(例如关闭窗口,刷新页面),它可能会或可能不会完成执行。时间取决于计算机的性能。例如,在我的计算机上,具有log语句的10ms超时仍然执行,因为我的浏览器没有时间刷新/关闭页面。

window.addEventListener("beforeunload", function (event) {
  setTimeout(() => {
    console.log("Timeout finished!"); // Odds are this will finish
  }, 10);
  console.log("Done!!");
});

然而,100毫秒的超时时间永远不会被执行:

window.addEventListener("beforeunload", function (event) {
  setTimeout(() => {
    console.log("Timeout finished!");
  }, 100);
  console.log("Done!!");
});

要保证函数运行完成的唯一方法是确保编写的代码是同步的,并且会阻塞事件循环,就像第一个示例中一样。


2
问题是,添加一个 while(!asyncCompleted); 阻塞器会起作用吗? - Vic
2
不行。while循环会阻塞异步事件的完成,因此你将被困在无限循环中。 - fny
1
如果一个页面触发了它的卸载事件,这意味着用户想要去其他地方。为什么你要干扰呢?我不知道。我的意思是,你能想象妈妈走进房间...... cmd + q,cmd + q,cmd + q...... 妈妈断绝了与儿子的关系。 - Ryan Wheale
6
这个功能的主要用途是检测用户是否填写了表单但没有提交,或者进行了某些未保存的操作,我们正在尝试提供帮助。 - jezmck
3
在您的第一个示例中,如果我想编写保证运行的代码,我应该把它放在哪里?我看到您已经创建了一个阻塞事件循环的sleep函数,但哪个console.log可以保证运行?如果要放置某些保证完成的内容(例如提交GET请求),应该放在哪里? - Kyle Vassella
显示剩余7条评论

10

非常出色! - Walle Cyril
文档说得不一样: “它旨在与visibilitychange事件结合使用(但不与unload和beforeunload事件结合使用)。” - StyleSh1t

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接