Closing Chrome window not sending data with sendBeacon in unload event handler
Asked Answered
U

2

7

I am trying to send data when the window closes to prevent 2 people from editing and overwriting each others data. Currently I am using a sendBeacon within a unload event handler.

FireFox:

  • Refresh: Works
  • Back button: Works
  • Close window: Works

Chrome:

  • Refresh: Works
  • Back button: Works
  • Close window: Doesn't work

Here is my code

function sendDataOnClose(edit,trans){

    var url = "../../save.php"; //This has a post request handler and works properly with other functions for saving data

    const data = JSON.stringify
    ({
      "translations": trans,
      "edit": edit
    });

    navigator.sendBeacon(url, data);
  }

function handleClose(){
    if(edit){
      console.log("sending a false when edit is: "+ edit)
      sendDataOnClose(false, translations);
    }
  }

window.addEventListener('unload', handleClose); 
Uboat answered 10/11, 2020 at 17:12 Comment(2)
Even though documentation says unload and beforeunload aren’t the right events to use with sendBeacon. Instead, use visibilitychange. it does not work on close with visibilitychange event either!Softhearted
It works on latest versions in all major browsers, I tested recently. You can check this post: https://mcmap.net/q/1627542/-why-is-time-on-site-data-not-getting-saved-in-db-when-accessed-from-firefox-browser Also, try replacing window.addEventListener('unload', handleClose); with 'beforeUnload' event which seems working normally in Chrome browsers. It shouldn't be a difference for you here. Believe me it's utilized a lot in timeonsite JS tracker and seems highly promising and reliable across a vast number of desktop browsers and mobile devices excluding IOS devices.Didache
P
2

The latest sendBeacon documentation on MDN, states "The navigator.sendBeacon() method asynchronously sends a small amount of data over HTTP to a web server. It’s intended to be used in combination with the visibilitychange event (but not with the unload and beforeunload events)."

To use the visibilitychange event like suggested, you could

document.addEventListener('visibilitychange', function() {
  if (document.visibilityState === 'hidden') {
    navigator.sendBeacon(handleClose);
  }
});

I have experienced similar issues with trying send data on the unload event. Is the user base all on desktop? Mobile devices don't reliably fire the unload event. The Page Lifecycle API provides the visibility change event and the pagehide events which could be used together to get closer to your desired result.

The Page Lifecycle API attempts to solve this problem by: Introducing and standardizing the concept of lifecycle states on the web. Defining new, system-initiated states that allow browsers to limit the resources that can be consumed by hidden or inactive tabs. Creating new APIs and events that allow web developers to respond to transitions to and from these new system-initiated states. source

The issue you are experiencing is likely more of an issue without how browsers suspend pages or discard them entirely. Unfortunately, browsers are not unified on how they do this, and to add to the complexity there is different behavior on desktop vs. mobile.

There are several threads that dive in deeper to this issue if you are interested. Until browsers standardize on this, I'm not sure there is an easy answer, such as "use x event".

Issue filed on Page Visibility

Issue on MDN's strints about sendBeacon

Philippine answered 23/12, 2020 at 14:25 Comment(2)
pagehide or visbilitychange doesn't fire either on tab close. That's the problem. I need any event that fires on window close and none worked.Softhearted
Please spell it like "visibility" not "visbility".Greenhorn
S
0

Thanks to hackers, many other things are removed for security reasons.

I noticed your question had the PHP tag as well; I will give you a, not good idea, but a functional one. Avoid on-close-page handles even JavaScript or frameworks just post with JavaScript a table database where you store time() and an target id then if timeout is maybe more than 30 sec you set then you will remove from table that stuff, and you will know that page isn't still working (translation: use a server "online users" idea (bad but necessary one like anything generates lots of traffic in an app).

Using these in JavaScript in the side client is bad idea and you open gates for bad guys that will exploit your app.

Shivaree answered 26/12, 2020 at 8:58 Comment(4)
I already have timeout on server side. I want to end timer when user closes the page.Softhearted
@Softhearted it's much simple then! the timeout should expire itself .: every time an user target or another user enter when the script start you should check all timeouts and remove them that is missing you is a target start time so you can handle on close page on server on timeout by verify start and stop reffering to current php time(); acording to a timeout differenceShivaree
Please edit the answer to include this idea.Greenhorn
@Janos Vinceller i could write a php mysql script to demonstrate "ONLINE USERS" start then stop php verifier handler but will not be what i thinkin 100% in my mind(in my case these situations code are present before i need it ,in my frameworks so i will not check on stackoverflow an answer i know yet).About the prevent hacking part I will not post anymore something could give idea to the fellows I try to stop inside my apps..So if you don't like the answer I could remove itShivaree

© 2022 - 2024 — McMap. All rights reserved.