javascript 如何在 AngularJS 中的 onbeforeunload 发送 HTTP 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21689233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to send an HTTP request onbeforeunload in AngularJS?
提问by Levon Tamrazov
I have a simple angular app that has two views that are loaded using ngRoute. I need to do some clean up on the server when the user navigates between views and when the user leaves the page (refreshes window, closes tab, or closes browser).
我有一个简单的 angular 应用程序,它有两个使用 ngRoute 加载的视图。当用户在视图之间导航以及用户离开页面(刷新窗口、关闭选项卡或关闭浏览器)时,我需要在服务器上进行一些清理。
My first stop was here: Showing alert in angularjs when user leaves a page. It solved the first case where the user navigates between views. I've handled the clean up like this:
我的第一站在这里:当用户离开页面时在 angularjs 中显示警报。它解决了用户在视图之间导航的第一种情况。我已经处理了这样的清理:
$scope.$on('$locationChangeStart', function (event) {
var answer = confirm("Are you sure you want to leave this page?")
if (answer) {
api.unlock($scope.id); //api is a service that I wrote. It uses angular $http service to handle communications and works in all other cases.
} else {
event.preventDefault();
}
});
However, I haven't been able to handle the case where the user leaves the page. Following the above answer and this Google Groups post: https://groups.google.com/forum/#!topic/angular/-PfujIEdeCYI tried this:
但是,我一直无法处理用户离开页面的情况。按照上面的答案和这个 Google Groups 帖子:https: //groups.google.com/forum/#!topic/angular/ -PfujIEdeCY我试过这个:
window.onbeforeunload = function (event) {
api.unlock($scope.id); //I don't necessarily need a confirmation dialogue, although that would be helpful.
};
But it did not work. Then I've read here: How to execute ajax function onbeforeunload?that the request needs to be synchronous and here: How to $http Synchronous call with AngularJSthat Angular does not support this (although this one might be outdated).
但它没有用。然后我在这里阅读: How to execute ajax function onbeforeunload? 请求需要是同步的,在这里:如何使用 AngularJS 进行 $http 同步调用,Angular 不支持这个(尽管这个可能已经过时了)。
I've also tried calling $http directly (without the service) but that did not work either. At this point I'm stuck. Any suggestions / leads would be really appreciated.
我也试过直接调用 $http(没有服务),但这也不起作用。在这一点上,我被困住了。任何建议/线索将不胜感激。
Thanks in advance!
提前致谢!
回答by Jose Ch.
The problem is that angular always make ASYNCHRONOUS calls with the $http service (and you can't change that behavior). Since the page exits before the $http service have a chance to emit the requests you are not getting the desired result.
问题是 angular 总是使用 $http 服务进行异步调用(并且您无法更改该行为)。由于页面在 $http 服务有机会发出请求之前退出,因此您没有获得所需的结果。
If you want a workarround without using any third party libraries try the following code:
如果您想要不使用任何第三方库的解决方法,请尝试以下代码:
var onBeforeUnload = function () {
var data = angular.toJson($scope.id...);//make sure you $scope is legal here...
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "apiURL/unlock", false);//the false is for making the call synchronous
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.setRequestHeader("Authorization", token);
xmlhttp.send(data);
}
It will block UI until the request is completed, so try to make the server fast or the user will notice.
它会阻塞 UI,直到请求完成,所以尽量让服务器速度快,否则用户会注意到。
回答by Jason Rust
Solution is to call $rootScope.$digest();
after firing your $http
calls in your onbeforeunload
callback. The reason is that angular's $http
methods wrap the config in an immediately resolved promise which means the ajax request doesn't actually get fired until the next tick. Other browsers appear to allow one more tick after the onbeforeunload
tick, but not IE11 (the only version of IE in which I tested). Forcing the digest cycle avoids the need to wait until the next tick.
解决方案是在您的回调中$rootScope.$digest();
触发您的呼叫后$http
调用onbeforeunload
。原因是 angular 的$http
方法将配置包装在一个立即解析的 promise 中,这意味着 ajax 请求在下一个滴答声之前实际上不会被触发。其他浏览器似乎允许在勾选后再onbeforeunload
勾选一个,但不允许 IE11(我测试的唯一 IE 版本)。强制消化循环避免了等到下一个滴答声的需要。