$apply in setTimeout
Posted
技术标签:
【中文标题】$apply in setTimeout【英文标题】: 【发布时间】:2014-02-23 16:34:36 【问题描述】:我知道$apply
用于连接 javascript 上下文和 AngularJS 上下文。
一个简单的例子如下:
模板:
<div>someVal</div>
控制器中的javascript:
setTimeout(function()
scope.$apply(function()scope.someVal = 123);
, 1000);
我们需要在上述情况下使用$apply
。
第一个问题:
如果我将上面的 javascript 修改为:
setTimeout(function()
scope.someVal = 123;
, 1000);
scope.$watch('someVal', function(val)
console.info(someVal);
);
没有控制台关于 someVal 修改为 123... 为什么?不能看超时回调中修改的表达式吗?
第二个问题:
如果我们像下面这样使用 ngSwitch 指令:
<div ng-switch on="sub">
<div ng-switch-when="a">
//state a
</div>
<div ng-switch-when="b">
//state b
</div>
</div>
当我在控制器中修改sub
时:
scope.sub = 'a';
setTimeout(function()
scope.sub = 'b';
, 1000);
无需使用$apply
!!!!为什么?
我发现 ngSwitch 指令使用$watch
来监控on
属性值。为什么ngSwitch可以看到超时回调中修改的scope属性??????
请告诉我上面 2 个问题的原因。
【问题讨论】:
第二个问题解决了! someVal 的 $apply 在其他 $apply 中触发,如jsfiddle.net/stefanqi/Jvak8。 【参考方案1】:来自AngularJs 文档
$apply() 用于从 Angular 框架外部执行 Angular 表达式。 (例如来自浏览器 DOM 事件、setTimeout、XHR 或第三方库)。因为我们正在调用 Angular 框架,所以我们需要执行适当的异常处理范围生命周期,执行 watch。
window.setTimeout 是一个 JavaScript 函数,所以无论你使用 setTimeout
你必须使用 $apply() 来更新模型。
您的第二个示例如果没有$apply()
将无法工作,我制作了一个demo 来澄清$watch
和$apply
的问题。请检查一下。
【讨论】:
抱歉,我无法访问您的演示。 你是对的!我发现 someVal 的 $apply 是在其他 $apply 中触发的...我对我遇到的情况做了一个小提琴:jsfiddle.net/stefanqi/Jvak8。无论如何,谢谢!【参考方案2】:您可以使用$timeout,它是 window.setTimeout 的包装器,这样您就不需要在回调中使用 $apply:
$超时(函数() 范围.someVal = 123; , 1000);
当您在 Angular 之外运行代码时,您需要一种方法让 Angular 和该值的观察者知道它已更改。这就是$apply 的用途,它将允许监听器触发
关于第二个问题,为什么范围在没有 $apply 的情况下更新,您应该以某种方式间接触发 $apply/$digest。为了给你一个更具体的答案,一个 Plunker 将是必要的,以检查你的代码中还有什么。
【讨论】:
【参考方案3】:使用 Angularjs $timeout service 代替 setTimeout,您将不需要 $apply。同样的事情是,如果您使用的是 jquery http 调用,请使用 angular http 服务来避免使用 $apply。
【讨论】:
以上是关于$apply in setTimeout的主要内容,如果未能解决你的问题,请参考以下文章
angularJS报错$apply already in progress的原因和解决方法
ST5222: Advanced Topics in Applied Statistics
[Compose] 21. Apply Natural Transformations in everyday work
WARNING: firstResult/maxResults specified with collection fetch; applying in memory!