Angular $ scope。$ apply vs $ timeout作为安全$ apply

时间:2014-04-14 21:30:54

标签: angularjs scope

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

据我所知:

  1. 在$ scope中包装代码。$ apply适用于您的场景 还没有进入摘要循环(又称jQuery事件),但如果正在进行摘要,则会引发错误
  2. 在没有延迟参数的$ timeout()调用中包装代码,无论是否已经在摘要周期中都有效
  3. 查看Angular源代码,看起来$ timeout调用$ rootScope。$ apply()。

    1. 如果摘要周期已在进行中,为什么$ timeout()也会引发错误?
    2. 最佳做法是使用$ scope。$ apply()当您确定某个摘要已经在进行中时,$ timeout()在需要它时是否安全?
    3. $ timeout()真的可以接受"安全申请",还是有问题?
    4. 感谢您的任何见解。

3 个答案:

答案 0 :(得分:60)

  

查看Angular源代码,看起来$ timeout会调用   $ rootScope。$申请()。

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

$timeout使用了未记录的Angular服务$browser。具体来说,它使用$browser.defer()通过window.setTimeout(fn, delay)异步延迟函数的执行,window.setTimeout将始终在Angular生命周期之外运行。只有$timeout点击后,您的$rootScope.$apply()才会调用FormController

  
      
  • 最佳做法是使用$ scope。$ apply()当您确定摘要不会在进行中时,$ timeout()在需要它时是否安全?
  •   

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

  
      
  • $ timeout()真的是一个可以接受的“安全申请”,还是有问题?
  •   

它应该始终是安全的,但是在我看来,你的方法总是应该以$ apply()为目标。我正在处理的当前Angular应用程序相当大,我们只需要依赖$ timeout而不是$ apply()。

答案 1 :(得分:13)

如果我们在应用程序中大量使用$ apply,我们可能会得到错误:$ digest正在进行中。这是因为一次可以运行一个$ digest周期。我们可以通过$ timeout或$ evalAsync来解决它。

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

我试图在Comparison of apply, timeout,digest and evalAsync解释它们。

可能会帮助你。

答案 2 :(得分:4)

据我所知,$timeoutsetTimeout的包装器,它隐含地调用$scope.$apply,这意味着它在角度生命周期之外运行,但启动角度生命周期本身。唯一的"陷阱"我能想到的是,如果你期望你的结果可以这个 $digest,你需要找到另一种方法来安全地应用" (其中,AFAIK,仅可通过$scope.$$phase获得)。