角度$ scope。$ apply与$ timeout作为安全的$ apply


68

我试图更好地理解在Angular中使用$ timeout服务作为一种“安全$ apply”方法的细微差别。基本上是在某些代码可以响应Angular事件或非Angular事件(例如jQuery或某些标准DOM事件)的情况下。

据我了解:

  1. 在$ scope。$ apply中包装代码适用于您尚未处于摘要循环(又称为jQuery事件)的情况,但是如果正在进行摘要,则会引发错误
  2. 在$ timeout()调用中包装没有延迟参数的代码无论是否已经在摘要周期中都有效

查看Angular源代码,看起来$ timeout调用了$ rootScope。$ apply()。

  1. 如果摘要周期已经在进行中,为什么$ timeout()也不会引发错误?
  2. 当您确定摘要尚未进行时,使用$ scope。$ apply()是最佳方法吗?在需要使用任一方法确保其安全性时,是使用$ timeout()吗?
  3. 是$ timeout()确实是可以接受的“安全应用”,还是有陷阱?

感谢您的任何见解。

Answers:


63

查看Angular源代码,看起来$ timeout调用了$ rootScope。$ apply()。

  • 如果摘要周期已经在进行中,为什么$ timeout()也不会引发错误?

$timeout使用未记录的Angular服务$browser。具体来说,它使用$browser.defer()通过延迟异步执行函数window.setTimeout(fn, delay),该函数将始终在Angular生命周期之外运行。仅window.setTimeout触发一次函数就会$timeout调用$rootScope.$apply()

  • 当您确定摘要尚未进行时,使用$ scope。$ apply()是最佳方法吗?在需要使用任一方法确保其安全性时,是使用$ timeout()吗?

我会这样说。另一个用例是,有时您需要访问一个$ scope变量,您知道该变量只会在摘要后初始化。一个简单的例子是,如果您想在控制器构造函数中将表单的状态设置为脏(无论出于何种原因)。没有$ timeout,FormController它不会被初始化并发布到$ scope上,因此$scope.yourform.setDirty()在$ timeout内包装可以确保FormController已被初始化。当然,只要给出另一个用例示例,就可以使用不带$ timeout的指令来完成所有这些操作。

  • 是$ timeout()确实是可以接受的“安全应用”,还是有陷阱?

它应该总是安全的,但是我认为您的go方法应该始终以$ apply()为目标。我正在使用的当前Angular应用程序相当大,我们只需要依赖$ timeout一次,而不是$ apply()。


在我的项目中,我有一个场景,我需要提高$ scope。$ digest()来捕获Angular视野之外发生的事件。超时是否仍然是safeApply或safeDigest的规范,还是已经在框架内巧妙地解决了?
TrueBlue

1
为什么您需要依靠$timeout而不是$apply?如果您不能共享代码,至少可以讨论一下基本原因吗?
trysis

14

如果我们在应用程序中大量使用$ apply,则可能会出现错误:$ digest已经在进行中。发生这种情况是因为一次可以运行一个$ digest循环。我们可以通过$ timeout或$ evalAsync解决它。

$ timeout不会产生像“ $ digest已经进行中”之类的错误,因为$ timeout告诉Angular,在当前周期之后,有一个超时等待,这样可以确保摘要周期与$输出之间不会发生任何冲突。超时将在新的$ digest周期执行。

我尝试在以下位置解释它们:apply,timeout,digest和evalAsync的比较

可能会对您有帮助。


感谢Rahul,文章很有趣。我觉得虽然缺少了推荐使用哪个或何时使用的建议。再次感谢。
Matty J

1
感谢Matty的投入。我认为,与可用的相比,$ evalAsync是更好的选择。
拉胡尔·加尔格

4

据我了解,它$timeout是一个包装器,在setTimeout其周围隐式调用$scope.$apply,这意味着它在角度生命周期之外运行,但会启动角度生命周期本身。我能想到的唯一“陷阱”是,如果您希望结果可用this $digest,则需要找到另一种“安全应用”的方法(AFIAK仅可通过访问$scope.$$phase)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.