Chrome Leave Site popup & beforeunload 等

Chrome Leave Site popup & beforeunload et al

提问人:mungnz 提问时间:10/19/2023 更新时间:10/19/2023 访问量:111

问:

我今天来上班,向一个公司网站的用户抱怨说,这些网站在导航到任何其他页面之前一直要求确认。我在更新 Chrome(我保持打开状态)之前和之后对其进行了测试,它从最新版本的 Chrome (118) 开始,适用于我和这个特定的网站。 此处的答案表明它是由 beforeunload 事件引起的,并禁用任何此类事件。我试过了,是的,这阻止了对话。

事情是这样的。当页面离开时,此站点将与服务器同步,并使用该事件来执行此操作。

...那么我该如何进行呢?

有没有另一种方式可以最后一次与服务器同步?我在执行之前卸载(等)错误吗?为什么它昨天工作,但今天不工作(我的意思是为什么 Chrome 修复了一些没有损坏的东西)?

我应该指出,我是自学成才的,虽然已经做了几年。我不像PHP那样喜欢JS方面,我在JS中所做的一切都感觉很糟糕,可能是错误的,但它使网站出来,因此可以使用它。

我曾尝试过使用 sendBeacon,但它从未真正起作用。也许我误解了它是如何工作的,也许它实际上不起作用,谁知道呢?因此,我使用了一个 post 方法,它只是 JQuery $.ajax 的包装器,但包含与特定站点相关的其他内容。

所以有一个通用的方法(它位于每个页面上加载的 app 对象中),它改编自过去的一些答案:

    addUnloadEvent( unloadEvent ) {
        let executed = false;
        let exec = function ( event ) {
            event.preventDefault();
            if ( !executed ) {
                executed = true;
                return unloadEvent();
            }
        };
        document.addEventListener( 'visibilitychange', function ( event ) {
            if ( document.visibilityState === 'hidden' ) {
                exec( event );
            }
        }, { capture : true } );
        window.addEventListener( "pagehide", exec, { capture : true } );
        window.addEventListener( "beforeunload", exec, { capture : true } );
        window.onbeforeunload = exec;
        window.addEventListener( 'unload', exec, { capture : true } );
    },

可能看起来像是一种霰弹枪方法,丑陋,糟糕,但你知道,我只需要让这个愚蠢的东西工作,这样客户就可以使用该网站。

不同的控制器有自己的 js 文件,用于扩展 app 方法,并且可以运行 init 方法,在一个特定控制器的特定 init 函数中,我们有这个:

....
        $app.addUnloadEvent( function () {
            return $app.syncBasketWithServer();
        } );
....

该方法是:

syncBasketWithServer() {
   return $app.post( '/order/syncBasket', { 'Basket' : $app.Basket }, function ( data ) {
            return data.status === 'success';
        } );
    }
JavaScript jQuery 谷歌浏览器

评论


答:

0赞 Bellian 10/19/2023 #1

因此,如果满足某些条件,则该事件将阻止用户离开:beforeunload

  • 调用事件对象的 preventDefault() 方法。
  • 将事件对象的 returnValue 属性设置为非空字符串值或任何其他真实值。
  • 从事件处理程序函数返回任何真实值

请参见:https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event

由于您在事件处理程序中做的第一件事是调用 preventDefault(),因此将触发该消息。

无论如何,当用户离开什么时提出请求(我会说)是不好的做法。 最好在找零时同步购物篮,而不是在休假时同步。 如果您需要这些信息,您可以发送请求,但据我所知,不能保证会发送请求。

如果您确实需要用户离开的信号,也许可以打开与用户的连接(Websocket,打开HTTP连接),如果用户断开连接,它将触发信标。

评论

0赞 mungnz 10/19/2023
谢谢。我认识到你所说的不良做法 - 我不久前更改了它,因为在此之前,它正在将每个更改发送到服务器,这导致了延迟......我以为我的代码是异步的,但显然有一些我不理解的东西,所以我的解决方案是存储更改并等待用户卸载页面。话虽如此,我后来做了进一步的更改,这似乎是异步发送的......无论如何,我更改了我的代码以在防止默认值之前检查更改,这暂时修复了......但会及时重新考虑整个事情。
0赞 Bellian 10/19/2023
如果直接发送更改,则可能会出现争用条件(先读后写)。更好的做法是实现更新队列。如果有更改,请触发更新。如果再次发生更改,请按住更改,直到第一次更改完成。此外,您可以更新UI,因为更改已确认已保存。但是,如果出现错误,您可以稍后恢复它。