Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple async/await resulting in "Navigation triggered outside Angular zone" in NS7 Angular 10. #2308

Open
jcassidyav opened this issue Dec 7, 2020 · 5 comments

Comments

@jcassidyav
Copy link

Environment
√ Component nativescript has 7.0.11 version and is up to date.
√ Component @nativescript/core has 7.0.13 version and is up to date.
√ Component @nativescript/android has 7.0.1 version and is up to date.
@angular/core 10.1.6
@nativescript/angular 10.0.0

Describe the bug
I am upgrading a project to NS7/Angular 10.
I have a button bound to an async method.
In the method if you await the result of something, then await a call to RouterExtensions.navigat(),
Then the error:
Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'
will be printed to the console.

There was no error in NS6 / Angular 8 in this scenario.

To Reproduce
<Button text="Log In" (tap)="onLogin()"></Button>

onLogin = async (): Promise<void> => {
        console.log("op1");
        await this.delay(1000);
        console.log("op2");
        await this.routerExtensions.navigate(["login"], { clearHistory: false });
    }

    async delay(ms: number) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
@jamescodesthings
Copy link

Is your tsconfig set to produce ES2017? I noticed zone issues popping up with async/await after the latest nativescript releases.

See angular/angular#31730, zone doesn't support native async/await in ES2017 targets.

Workaround is to wrap your NgZone stuff in a ngzone.run(() => { [... something to do in a zone]}) call or to fall back to Promises where this doesn't work.

@jcassidyav
Copy link
Author

Yes set to ES2017 alight. that is a real gotcha with moving to NS10.

@edusperoni
Copy link
Collaborator

I believe Angular in general is making a move away from zone.js. With the new async/await, it becomes impossible to target es2017 and have angular work consistently. With IE finally dying, things like async/await are already supported for 94.42% of users (https://caniuse.com/?search=async), and it seems like es5 might be on the way out in the coming years. This means that libraries will likely drop es5 support, and targeting es2017 or lower will not save you from zone not working, so the angular team will have to come up with something akin to ngcc to transform native async/await to es5 or add babel to the webpack config.

Zone also has a number of issues currently. If you run:

this.zone.runOutsideAngular(() => {
  setTimeout(() => {
    for(let i=0; i<100; i++) {
      this.zone.run(() => {});
    }
  }, 0);
});

Change detection will run 100 times (basically every time you exit the angular zone through zone.run). Thankfully there are a couple of things that improve it, ngZoneEventCoalescing will coalesce events into a single CD and ngZoneRunCoalescing (set to be released in 11.1, implemented in 11.1.0-next.0).

Coalescing is also the way angular ivy's new markDirty API works, which I believe will be the new standard for CD. markDirty marks the component+all parents up to the root as dirty and schedules a CD with requestAnimationFrame or setTimeout if not already scheduled.

This is 100% my speculation, but I expect zone to be deprecated in the future (not very soon though) as people are encouraged to use markDirty(this) or ChangeDetectorRef, or even better, async and other pipes (which will probably be adapted to schedule CD).

Zone absolutely was a great idea at the time and it's amazing how well it worked so far, but as javascript evolves, it'll suffer more and more due to not being considered by TC39 and the proposal itself being withdrawn (https://github.com/domenic/zones). Zone itself works by monkey patching APIs, which is also why a lot of things in native platforms like NativeScript require you to manually call ngzone.run (with our rewrite of the angular integration, this will be greatly improved. Also we'll recommend turning on ngZoneEventCoalescing and ngZoneRunCoalescing for very big performance improvements!)

Here are some great resources:

Reactive Angular with ngrx/component: https://christiankohler.net/reactive-angular-with-ngrx-component
"Zones are great until they are not.", Rob Wormald - Keynote - What’s New and Coming in Angular | AngularUP 2019: https://www.youtube.com/watch?v=-32nh-pGXaU&feature=youtu.be&t=19m10s

@iamabs2001
Copy link

try to produce ES2015

@two-bridges
Copy link
Sponsor

"target": "es2015" does fix the problem for me, @iamabs2001 .

I'm doing some more testing to make sure it doesn't break anything before downgrading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants