Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

wait for promises in onbeforeunload

I want to send a $http.get if the page gets closed. Then I stumbold upon a problem where
promises can't get resolved because if this one last method returns, the page gets destroyed.

The following does not work because onbeforeunload can't resolve promises / does not wait for them:

window.onbeforeunload = function(
    $http.get('http://someth.ing/update-state?page=unloaded').then(function(){
        // never called... never sent...
    }

}

I know, you can use default sync HTTP Methods but the question is generally how could we sync/wait for promises to resolve here.

My idea would be something like this:

window.onbeforeunload = function(){
    var ready = false;

    $http.get('http://someth.ing/update-state?page=unloaded').then(function(){
         ready=true;
    }

    // I don't see any other opportunity to sync a promise here than this:
    while(!ready) angular.noop();
    // big question: did $http call the server now? Can we finally return in this method to let the browser 'exit' the page?
}

RFC

like image 956
noXi Avatar asked Apr 02 '16 21:04

noXi


People also ask

What triggers Onbeforeunload?

The onbeforeunload event occurs when the document is about to be unloaded. This event allows you to display a message in a confirmation dialog box to inform the user whether he/she wants to stay or leave the current page. The default message that appears in the confirmation box, is different in different browsers.

What does Window Onbeforeunload do?

The beforeunload event is fired when the window, the document and its resources are about to be unloaded. The document is still visible and the event is still cancelable at this point. This event enables a web page to trigger a confirmation dialog asking the user if they really want to leave the page.

How do I cancel Onbeforeunload?

Cancelable: The beforeunload event can be canceled by user interaction: // by https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload#Example window. addEventListener("beforeunload", function(event) { event. preventDefault(); // Cancel the event as stated by the standard.

What is window Onbeforeunload null?

window. onbeforeunload = null; so what you would have to do is - add a click event listener to all your buttons and links (which redirect user to a different URI) and inside that listener - set the onbeforeunload event listener to null once they are clicked (before proceeding with the normal link/button action.


1 Answers

You have 2 problems:

  • You are using a callback (event handler) intended as "last-chance", this event handler, if browsers typically treat it in a special way, and doing any kind of long-running operations here is not intended.
  • Standard operation workflow will resume after this callback exits, meaning that any asynchronous operations are likely not going to be finished, especially if they are guaranteed to not be executed in the current tick (promises fall under this category, they will never be resolved synchronously by design).

So what to do to work within these limitations? You have a few options:

  • Avoid asynchronous code. You can do the http fetch before you get to this point, store the results and use them synchronously inside onbeforeunload.

  • Use ServiceWorker to continue doing work after page has been terminated. Again, I suggest creating, registring and activating worker before you get to handling onbeforeupload. During onbeforeupload handling - you want to postMessage to your worker, asking it to do some work for you. This option comes with 2 caveats:

  • ServiceWorker is not a released standard, it's still a draft, expect API changes, browser support issues and, indeed, potential scrapping of the API all together.

  • Worker has no direct access to your page, you have to be aware of that, what what it means. For example - no window object, no libraries loaded on your page, separate script for the worker, exchange of data via explicit messages only - to name a few.

like image 61
travnik Avatar answered Sep 20 '22 09:09

travnik