Introduction Zoneless change detection是Angular 18引入的一个新特性,该特性能让Angular在不依赖zone.js
的情况下进行更新检测。下面我们来看一下如何使用这个新特性。
Why remove Zone.js?
Reducing initial bundle size, Zone.js is about 30KB raw and around 10KB gzipped. Remove it can significantly save the initial load time.
Avoid unnecessary change detection cycles: Zone.js notify Angular to run change detection on every async operation, but it doesn’t actually know whether these operations change any data.
Improve debugging experience, Zone.js can make stack traces harder to read.
Integration steps Create an Angular 18 project 1 npx @angular/cli@18 new my-zoneless-app
Enable zoneless change detection in standalone bootstrap app.
Open file app.config.ts
under src/app
folder.
Remove the following line1 provideZoneChangeDetection ({ eventCoalescing : true }),
Add the following line1 provideExperimentalZonelessChangeDetection (),
Enable zoneless change detection in traditional Module based app. 1 2 3 4 5 6 platformBrowser ().bootstrapModule (AppModule );@NgModule ({ providers : [provideExperimentalZonelessChangeDetection ()] }) export class AppModule {}
Remove zone.js from your project Remove zone.js from file angular.json
or project.json
for Nx based project.
Open file angular.json
or project.json
.
Remove the following line from architect | build | options
1 2 3 "polyfills" : [ "zone.js" ] ,
Remove the following line from architect | test | options
1 2 3 4 "polyfills" : [ "zone.js" , "zone.js/testing" ] ,
Old app with polyfills.ts
For old Angular app with an explicit polyfill.ts
file, you can remove import 'zone.js'
and import 'zone.js/testing'
from polyfills.ts
.
Uninstall zone.js
Start your app
How to make your app work with zoneless change detection 对于开启了zoneless change detection的应用,Angular需要依赖核心API的通知才能进行更新检测,这些通知包括:
ChangeDetectorRef.markForCheck
(called automatically by AsyncPipe
)
ComponentRef.setInput
Updating a signal
that’s read in a template
Bound host or template listeners callbacks
Attaching a view that was marked dirty by one of the above
除了以上几种情况,Angular不会自动进行更新检测,比如setTimeout
、setInterval
、Promise.then
、fetch
等异步操作,这些操作不会触发更新检测,需要手动调用ChangeDetectorRef.markForCheck
来通知Angular进行更新检测。
Use signal for simple value 1 2 3 4 5 6 7 8 name = signal ('zdd' ); ngOnInit ( ) { setTimeout (() => { this .name .set ('Philip' ) }, 1000 ) }
Note that, you need to use name()
instead of name
in your template.
1 2 <p > Hello, I'm {{name()}}</p >
Use signal for complex value 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface User { id : string ; title : string ; } user = signal<User | null >(null ); fetchData ( ) { return fetch ('https://jsonplaceholder.typicode.com/todos/1' ) .then (response => response.json ()) } ngOnInit ( ) { this .fetchData ().then (res => { this .user .set (res); }); }
Note again, you need to use user()
instead of user
in your template.
1 2 3 4 5 <div > user id: {{user()?.id}} user name: {{user()?.title}} </div >
Manually call cdf.markForCheck
Note, setTimeout
won’t call change detection automatically, you need to call cdf.markForCheck
manually.
1 2 3 4 5 6 7 8 9 constructor (private cdf : ChangeDetectorRef ) {}name = 'zdd' ngOnInit ( ) { setTimeout (() => { this .name = 'Philip' ; this .cdf .markForCheck (); }, 1000 ) }
for fetch
api, you need to call cdf.markForCheck
manually as well.
1 2 3 4 5 6 7 8 9 10 11 fetchData ( ) { return fetch ('https://jsonplaceholder.typicode.com/todos/1' ) .then (response => response.json ()) } ngOnInit ( ) { this .fetchData ().then (res => { this .user = res; this .cdf .markForCheck (); }); }
References
https://angular.dev/guide/experimental/zoneless
https://angular.love/the-latest-in-angular-change-detection-zoneless-signals