Javascript / angular: 从onunload执行异步http

Javascript / angular: perform asynchronous http from onunload

我正在使用一个网络应用程序来锁定服务器上的资源。要解锁它们,它必须使用 HTTP DELETE 删除服务器上的资源。我知道这不可靠,还有定期清理 运行 来解锁它们,但目标是尽快解锁资源。

我无法更改锁定架构(这不是我的系统),我只能尽力解锁。

我需要解锁的一点是当标签页或浏览器关闭时。首先,我正在处理 onbeforeunload,如果文档脏了,提示用户确认他们要关闭:

$window.onbeforeunload = function() {
    if (documentIsDirty) {
        return "Some prompt text";
    }
};

我无法从 onbeforeunload 中解锁,因为用户可能会选择取消关闭。但是在onbeforeunload和onunload之间没有事件(如果我错了请纠正我)。

如果我尝试从 onunload 中进行调用,那么 tab/session 会在 onunload 函数 returns 时立即被销毁。问题是,那是在 http 请求完成之前,事实证明资源实际上并没有解锁。

$window.onunload = function() {
    $http.delete('/a/lock/url');

    // I've tried forcing a digest cycle to try and flush the request
    // through, but it never gets sent either way
    $rootScope.$digest();
};

现在,我知道在 Javascript 中实际 阻止 是令人厌恶的,但似乎一旦加载 returns,她就写了这么多。

有什么方法可以阻止直到 http 请求实际完成,并防止 onunload 在此之前返回?

[更新] 解决方案如下 - 同步使用 XMLHttpRequest。它已被大声弃用,但(在撰写本文时)至少在 Chrome.

中仍然有效
var request = new XMLHttpRequest();
request.open('DELETE', url, false);
request.setRequestHeader('X-XSRF-TOKEN', myXSRFToken);
request.send();

$http 将始终异步执行请求,因为在内部它只是使用 XMLHttpRequest 并始终将 true 作为第三个参数传递给请求的 open 函数。来自 XMLHttpRequest's open function 的 MDN 文档:

An optional Boolean parameter, defaulting to true, indicating whether or not to perform the operation asynchronously. If this value is false, the send()method does not return until the response is received.

如果你想做一个同步请求,你可以直接使用XMLHttpRequest并将false作为第三个参数传递给open。因为这是网站关闭的时候,所以无论如何都没有必要使用 Angular 的 $http。

最近,在做这种 activity 时遇到了同样的问题,并使用 navigator.sendBeacon() 解决了这个问题。navigator.sendBeacon() 方法通过 HTTP 异步发送少量数据到网络服务器。对于最新的浏览器,你可以这样做

window.addEventListener('beforeunload', function (event) {
    data = new FormData();
    // for CSRF Token
    token = $('meta[name="csrf-token"]').attr('content');
    data.append("key", value);
    data.append("authenticity_token", token);
  
    navigator.sendBeacon("URL", data);
    
    // Cancel the event as stated by the standard.
    event.preventDefault();
    // Chrome requires returnValue to be set.
    event.returnValue = 'Are you sure you want to leave this page without saving?';
  });

更多详情请查看Navigator.sendBeacon() and Window: beforeunload event