【问题标题】:Angular $scope.$apply vs $timeout as a safe $applyAngular $scope.$apply 与 $timeout 作为安全的 $apply
【发布时间】:2014-05-29 01:06:40
【问题描述】:

我试图更好地理解在 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() 真的是一个可以接受的“安全应用”吗?还是有陷阱?

感谢您的任何见解。

【问题讨论】:

    标签: angularjs scope


    【解决方案1】:

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

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

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

    也许对你有帮助。

    【讨论】:

    • 感谢 Rahul,文章很有趣。我觉得它缺少的是建议使用哪个,或者什么时候使用。再次感谢。
    • 感谢马蒂的意见。在我看来,与可用的相比,$evalAsync 是更好的选择。
    【解决方案2】:

    查看 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 to 方法应该始终针对 $apply()。我正在开发的当前 Angular 应用程序相当大,我们只需要依赖一次 $timeout 而不是 $apply()。

    【讨论】:

    • 在我的项目中,我有一个场景,我需要提高 $scope.$digest() 以捕获发生在 Angular 视图之外的事件。超时是否仍然是 safeApply 或 safeDigest 的规范,还是已在框架内巧妙地修复?
    • 为什么需要依赖$timeout 而不是$apply?如果不能共享代码,至少能谈谈基本原因吗?
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2016-08-31
      • 2015-10-29
      • 2015-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多