wait for promises in onbeforeunload
Asked Answered
C

1

19

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

Cavort answered 2/4, 2016 at 21:52 Comment(3)
If you're using async Ajax in onbeforeunload, there are simply no guarantees and no supported ways to do that. Though it has its own issues, it is possible to send synchronous Ajax (at a risk of sacrificing the user experience). Usually, the better solution is to solve whatever problem you're trying to solve a different way. Some people use the close of a webSocket connection as seen on the server as a notification of when the page has been closed.Bolyard
WebSockets could be good solution. ThanksCavort
Were you able to figure it out using webSocketsTuberculous
K
7

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.

Kickstand answered 28/3, 2018 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.