mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
Close #39296 Fix an issue that `markDirty()` will not trigger change detection. The case is for example we have the following component. ``` export class AppComponent implements OnInit { constructor(private router: Router) {} ngOnInit() { this.router.events .pipe(filter((e) => e instanceof NavigationEnd)) .subscribe(() => ɵmarkDirty(this)); } } export class CounterComponent implements OnInit, OnDestroy { ngOnInit() { this.countSubject.pipe(takeUntil(this.destroy)).subscribe((count) => { this.count = count; ɵmarkDirty(this); }); } ``` Then the app navigate from `AppComponent` to `CounterComponent`, so there are 2 `markDirty()` call at in a row. The `1st` call is from `AppComponent` when router changed, the `2nd` call is from `CounterComponent.ngOnInit()`. And the `markDirty()->scheduleTick()` code look like this ``` function scheduleTick(rootContext, flags) { const nothingScheduled = rootContext.flags === 0 /* Empty */; rootContext.flags |= flags; if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) { rootContext.schedule(() => { ... if (rootContext.flags & RootContextFlags.DetectChanges) rootContext.flags &= ~RootContextFlags.DetectChanges; tickContext(); rootContext.clean = _CLEAN_PROMISE; ... }); ``` So in this case, the `1st` markDirty() will 1. set rootContext.flags = 1 2. before `tickContext()`, reset rootContext.flags = 0 3. inside `tickContext()`, it will call `CounterComponent.ngOnint()`, so the `2nd` markDirty() is called. 4. and the `2nd` scheduleTick is called, `nothingScheduled` is true, but rootContext.clean is not `_CLEAN_PROMISE` yet, since the `1st` markDirty tick is still running. 5. So nowhere will reset the `rootContext.flags`. 6. then in the future, any other `markDirty()` call will not trigger the tick, since `nothingScheduled` is always false. So `nothingScheduled` means no tick is scheduled, `rootContext.clean === _CLEAN_PROMISE` means no tick is running. So we should set the flags to `rootContext` only when `no tick is scheudled or running`. PR Close #39316 |
||
|---|---|---|
| .. | ||
| i18n | ||
| instructions | ||
| interfaces | ||
| ivy | ||
| jit | ||
| perf | ||
| styling_next | ||
| util | ||
| BUILD.bazel | ||
| change_detection_spec.ts | ||
| common_with_def.ts | ||
| component_ref_spec.ts | ||
| component_spec.ts | ||
| di_spec.ts | ||
| domino.d.ts | ||
| global_utils_spec.ts | ||
| i18n_debug_spec.ts | ||
| imported_renderer2.ts | ||
| instructions_spec.ts | ||
| integration_spec.ts | ||
| is_shape_of.ts | ||
| is_shape_of_spec.ts | ||
| jit_environment_spec.ts | ||
| listeners_spec.ts | ||
| load_domino.ts | ||
| matchers.ts | ||
| matchers_spec.ts | ||
| metadata_spec.ts | ||
| node_selector_matcher_spec.ts | ||
| perfCounter_spec.ts | ||
| pipe_spec.ts | ||
| providers_spec.ts | ||
| query_spec.ts | ||
| render_util.ts | ||
| renderer_factory_spec.ts | ||
| testing_spec.ts | ||
| utils.ts | ||
| view_container_ref_spec.ts | ||
| view_fixture.ts | ||
| view_utils_spec.ts | ||