48

我在我的角度项目中遇到了一个错误,最终通过将我的代码包装到

this.zone.run(() => {/* my code here */});

this answer所述。

我之前的理解zone是,Angular 无法检测到callbacks第三方库的异步所做的更改,因为“它们不在 Angular 中zone”。如果我单击 a button,则触发的事件不是浏览器的本机click事件,而是由 angular 创建的自定义(修补)click事件,其handlerzoneso angular 中运行会知道其回调处理程序所做的更改。

但是我无法理解通过router.navigate()在第三方回调中运行会产生这个问题(如this github issue所示)。不是Routerangularservice本身吗?zone为什么在第三方调用时它不会自动通知 Angular callback

我通过router.navigate在 NGXS 的 state reducer 中使用遇到了这个问题。

我的问题是:

有人能解释一下我什么时候需要把我的代码包装进去NgZone吗?

调试几个小时并意识到我的代码脱离了zone上下文是令人厌烦的。

4

3 回答 3

14

ngZone.runOutsideAngular() - 这会在角度区域之外运行代码。

  • 当某个事件被触发时,它会告诉 angular 来检测变化。
  • 如果您使用的是 mouseUp() 或 mouseDown() 事件,那么在每次更改时它都会告诉 angular 来检测更改。
  • 如果我们不希望这些更改在 Angular 运行时发生(这会降低应用程序的性能),我们可以在 Angular 区域之外运行它。
  • 与此相反,如果我们非常想获得每一个更新,那么我们可以使用 ngZone.run()。意味着它将正常运行更改检测。

Angular 本身在后台使用 ngZone 来检测更改

所以,如果我们已经离开了角度区域,那么我们使用ngZone.run()

于 2019-10-09T12:55:55.133 回答
8

ngZone.run()在对路由进行单元测试时特别有用。

it('should redirect if condition true, fakeAsync(() => {
  router.navigate(['']);
  fixture.ngZone.run(() => {
    component.redirectIfConditionTrue();
  });
  tick();
  expect(location.path()).toBe('/AgentLeadsManager');
}));
  • 资料来源:这是我唯一一次使用它
于 2019-10-18T15:51:36.380 回答
7

Zone.js 是一个执行上下文,用于跟踪和拦截异步操作,例如:DOM 事件 ( click, keydown, keyup, etc), setTimeout, setInterval. XMLHttpRequests)

NgZone 只是围绕Zone.js's API 的包装 Angular 服务。

Angular 团队决定在使用 Angular 时需要对执行上下文进行抽象,因此他们在 Angular 中围绕它构建了 Zone.js 和包装器(非正式地 - 适配器模式)。

所以基本上回答你的问题:在处理与 Zone.js 中的 Angular 运行上下文无关的任何类型的 3rd 方库时(除非你决定不需要执行上下文并且你可以在没有它的情况下使用NoopNgZone

资源

于 2019-10-18T17:18:35.040 回答