我试图更好地理解在 Angular 中使用 $timeout 服务作为一种“安全 $apply”方法的细微差别。基本上在一段代码可以运行以响应 Angular 事件或非 Angular 事件(如 jQuery 或某些标准 DOM 事件)的情况下。
据我了解:
在 $scope.$apply 中包装代码适用于您尚未处于摘要循环(也称为 jQuery 事件)但如果摘要正在进行中会引发错误的情况 在 $timeout() 调用中包装代码而不延迟参数是否已经在摘要循环中有效
查看 Angular 源代码,看起来 $timeout 调用了 $rootScope.$apply()。
如果摘要周期已经在进行中,为什么 $timeout() 也不会引发错误?当您确定摘要不会正在进行时,使用 $scope.$apply() 的最佳实践是,而在需要以任何方式保证安全时使用 $timeout() 是最佳实践吗? $timeout() 真的是一个可以接受的“安全应用”,还是有陷阱?
感谢您的任何见解。
查看 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()。
如果我们在应用程序中大量使用 $apply,我们可能会得到 Error: $digest already in progress。这是因为一次可以运行一个 $digest 循环。我们可以通过 $timeout 或 $evalAsync 来解决它。
$timeout 不会产生像“$digest already in progress”这样的错误,因为 $timeout 告诉 Angular 在当前周期之后,有一个超时等待,这样可以确保摘要周期之间不会有任何冲突,从而输出 $ timeout 将在新的 $digest 周期上执行。
我试图在 Comparison of apply, timeout,digest and evalAsync 处解释它们。
也许它会帮助你。
据我了解,$timeout
是 setTimeout
的包装器,它隐式调用 $scope.$apply
,这意味着它在角度生命周期之外运行,但会启动角度生命周期本身。我能想到的唯一“陷阱”是,如果您希望您的结果可用this $digest
,您需要找到另一种“安全应用”的方法(AFAIK 是只能通过 $scope.$$phase
获得)。
不定期副业成功案例分享
$timeout
而不是$apply
?如果您不能共享代码,您至少可以讨论一下基本原因吗?