经过一番分析,这似乎是 Firefox 中 $interval 和模式对话框之间令人惊讶的交互。
问题是什么 ?
调用堆栈显示了一些奇怪的东西:一个 AngularJS 函数tick在控制器内调用start功能。这怎么可能?
嗯,看来Firefox 在显示模式对话框时不会暂停超时/间隔功能 http://bytes.com/topic/javascript/answers/465001-modal-dialog-doesnt-threads-sleep-firefox:这允许调用配置的超时和间隔回调在当前执行的 javascript 代码的顶部.
在上述情况下,start函数被调用时带有$apply序列(当单击按钮时由 AngularJS 启动)以及当$间隔回调在顶部执行start函数,第二个$apply序列启动(由 AngularJS)=> 繁荣,$apply 已在进行中错误被提出。
一个可能的解决方案
定义一个新的confirm服务(改编自this http://www.bennadel.com/blog/2808-asking-the-user-to-confirm-location-or-route-changes-in-angularjs.htm and that http://www.bennadel.com/blog/2632-creating-asynchronous-alerts-prompts-and-confirms-in-angularjs.htm博客文章):
// This factory defines an asynchronous wrapper to the native confirm() method. It returns a
// promise that will be "resolved" if the user agrees to the confirmation; or
// will be "rejected" if the user cancels the confirmation.
mod.factory("confirm", function ($window, $q, $timeout) {
// Define promise-based confirm() method.
function confirm(message) {
var defer = $q.defer();
$timeout(function () {
if ($window.confirm(message)) {
defer.resolve(true);
}
else {
defer.reject(false);
}
}, 0, false);
return defer.promise;
}
return confirm;
});
...并按以下方式使用它:
// this function starts some service on the backend
$scope.start = function() {
confirm('Are you sure ?').then(function () {
$http.post('start.do').then(function (res) {
$scope.started = true;
});
});
};
// this function stops some service on the backend
$scope.stop = function() {
confirm('Are you sure ?').then(function () {
$http.post('stop.do').then(function (res) {
$scope.started = false;
});
});
};
该解决方案之所以有效,是因为模式对话框是在间隔的回调执行内打开的,并且(我相信)间隔/超时执行是由 javascript VM 序列化的。