AngularJS全局变量监听:$rootScope.$watch的副作用与正确清理方式
本文探讨AngularJS中监听全局变量的正确姿势。直接在全局$rootScope上注册$watch会导致所有控制器变更时触发回调,引发性能问题。文章通过源码分析指出,可通过保存注销函数手动清理监听,或利用$destroy机制自动处理。
AngularJS全局变量监听:$rootScope.$watch的副作用与正确清理方式
若仅需知晓最终方案:
$scope.$watch($rootScope.xxx,function(newVal,oldVal){
//do something
})
随即会有人质疑为何不采用:
$rootScope.$watch("xxx",function(newVal,oldVal){
//do something
})
基于近期遭遇的一个bug,阐述采用首种方式的缘由。
逻辑流程如图所示,初始阶段我采用了 $rootScope.$watch 的实现方式。鉴于 angularjs 在 $rootScope 上注册的 watch 具有全局生效特性,而该全局变量恰好承载订单信息,这意味着多个 controller 均会对其执行修改操作。任何一次修改都会导致 $rootScope.$watch 触发并进入其他 controller。此情形可类比参考 $rootScope 上的 $broadcast 所引发的全局广播行为。
这并非唯一的解决路径,查阅 angular 源码即可发现 watch 方法源码中存在如下代码片段:
return function deregisterWatch() {
if (arrayRemove(array, watcher) >= 0) {
incrementWatchersCount(scope, -1);
}
lastDirtyWatch = null;
};
该段代码表明,手动清理 watch 是可行的操作。例如:
var watcher = $rootScope.$watch("xxx",function(){});
//手动清除 watcher
watcher();
实现逻辑依然简洁,上述方法同样适用于 scope 上的 watch。
深入探究至此,产生疑虑:在 $scope 环境下是否会被自动清理?为此,继续查阅源码,我在 $destroy 方法内部发现了如下代码:
// Disable listeners, watchers and apply/digest methods
this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
this.$on = this.$watch = this.$watchGroup = function() {
return noop;
};
this.$$listeners = {};
上述代码即为本文所介绍的 Angularjs 全局变量被作用域监听的正确姿势,期望能对大家有所助益。本文撰写水平有限,恳请各位专家不吝指正。
JS中使用位运算(~~)和一元加号(+)快速转换字符串为整数
2026-11-03 22:41:12
怎么使用命令行批量格式化项目中的JS文件
2026-11-03 19:04:42
JS代码美化后报错怎么办?常见格式化冲突解决方法
2026-11-03 18:47:01
不用moment.js,怎么用原生JS Intl API格式化时间戳
2026-11-03 18:10:30
原生JS与dayjs获取当前日期的代码对比
2026-11-03 17:57:26
