Artikel ini akan membawa anda untuk mengetahui lebih lanjut tentang pengesanan perubahan dalam Angular, dan memperkenalkan kepada anda mekanisme kemas kini DOM Angular, masalah apa yang boleh diselesaikan oleh pengesanan perubahan, dsb.
Melalui artikel ini, anda boleh membantu anda memperoleh pengetahuan ini:
Mari kita lihat demo paling mudah
Apabila butang diklik, kami menukar komponen Untuk atribut nama, nilai yang diubah juga dipaparkan dalam DOM dalam sekejap, yang kelihatan agak "ajaib".
Jika anda mencetak interText dalam DOM sebenar sejurus selepas penyataan perubahan elemen, anda mendapati ia masih nilai lama, tetapi nilai dalam paparan jelas mempunyai berubah. Apakah sebenarnya yang berlaku dalam dua keping kod ini? Jika anda juga tertanya-tanya tentang perkara ini, maka sertai saya untuk mendedahkan jawapannya.
Mari kita ingat dengan teliti apa yang baru sahaja berlaku:
Klik butang
Perubahan nilai
Jika anda menggunakan JS asli untuk menulis kod ini, paparan pasti tidak akan berubah selepas mengklik butang, tetapi dalam Angular, paparan akan berubah. Jika anda mempunyai pemahaman yang sedikit mendalam tentang Angular, anda akan mengetahui tentang perpustakaan yang dipanggil zone.js Jika anda melihat dengan teliti, anda akan mendapati bahawa zone.js melakukan lapisan pemprosesan untuk semua peristiwa yang mungkin mengubah nilai, seperti. :
Angular juga menyediakan kami cara untuk melumpuhkan zon.js.
Selepas melumpuhkan zon, apabila kami mengklik butang sekali lagi, paparan tidak dikemas kini.
Dengan rasa ingin tahu, kami menemui kod kunci untuk kemas kini paparan dalam kod sumber Sudut
Kali ini kami memanggilnya secara manual dalam kaedah kod.
Seperti yang dijangkakan! Pandangan dikemas kini, dan apa yang lebih mengejutkan ialah teks dalam yang dicetak juga dikemas kini!
Pada ketika ini, kami telah membuat kesimpulan bahawa kemas kini DOM bergantung pada pencetus tick(), dan zone.js membantu pembangun menjimatkan keperluan untuk mencetuskan manual .
Baiklah, selepas ujian kecil, mari kita lihat dengan lebih dekat apa yang berlaku di sebalik kemas kini Angular view.
Mari lihat. pertama Ralat sedemikian, menukar nilai nama komponen induk dalam ngOnInit komponen anak, mengakibatkan mesej ralat yang mesti dihadapi oleh semua orang
Walau bagaimanapun, menulis dengan cara ini tidak selalu menghasilkan ralat Sebagai contoh, jika kita mengalih keluar atribut input komponen anak, muat semula ia dan mendapati bahawa kod yang sama boleh dijalankan, dan nama bagi. komponen induk boleh ditukar seperti biasa.
emmm... Hilang dalam fikiran...
Mungkin anda seperti saya ketika mula-mula belajar Angular, mencari soalan ini dalam stackoverflow, copy Saya menemui kod yang saya tidak tahu mengapa ia berfungsi, jadi saya menampalnya secara terus Apabila saya menghadapi masalah ini sekali lagi, saya terus mencari dan menyalin dan menampal dalam stackoverflow, dan seterusnya...
Seiring dengan berlalunya masa, anda yang mahir dalam pelbagai CRUD semakin tidak berpuas hati dengan pengaturcaraan berorientasikan stackoverflow ini Anda mula terus mencari jawapan kepada soalan dalam komuniti, dokumen dan forum, tetapi selepas membaca mereka Dari jawapan dan artikel, nampaknya saya hanya tahu bahawa ada sesuatu yang dipanggil Pengesanan Perubahan, tetapi saya tidak dapat menjelaskan dengan tepat apa yang menyebabkan pepijat ini Jika anda mempunyai pengalaman yang sama seperti saya, Jika anda mempunyai mendalam memahami, maka teruskan meneroka kebenaran!
Apabila kita menukar data dalam model, lapisan rangka kerja perlu tahu:
Semua orang mesti biasa dengan Virtual Dom dalam React menentukan bahagian DOM yang hendak dikemas kini dengan membandingkan keadaan baharu dan keadaan lama DOM, bukannya mengemas kini semua. DOM. Ini juga pengesanan perubahan dalam Angular.
Keseluruhan aplikasi Angular ialah pepohon komponen Adalah mustahil untuk perubahan dalam mana-mana komponen untuk mencetuskan kemas kini semua komponen Ini adalah terlalu tidak cekap dan terlalu memakan masa Sebagai contoh, jika pengguna menukar keadaan daripada butang, maka pendekatan terbaik ialah mengemas kini hanya gaya atau teks butang ini dan bukannya mengemas kini keseluruhan aplikasi Ini adalah tujuan pengesanan perubahan.
Secara lalai (ChangeDetectionStrategy.Default
), apabila pengesanan perubahan komponen induk berlaku, komponen anak juga akan mencetuskan pengesanan perubahan.
(CD
ialah changeDetection
)
Setiap kali perubahan dikesan, keadaan lama dan baharu akan dibandingkan dikesan dua kali (persekitaran pembangunan Jika keputusan di bawah) tidak konsisten, ralat akan dilaporkan, contohnya:
Expression has changed after it was checked
Ini juga menerangkan sebab menukar nilai komponen induk dalam komponen anak akan melaporkan ralat.
Tetapi! Dalam dua contoh sebelumnya, kami menukar nilai komponen induk dalam komponen anak Hanya yang pertama melaporkan ralat, dan yang kedua boleh dikemas kini secara normal Jika anda juga keliru tentang perbezaan sebenar antara mereka, Kemudian baca pada~
Pertama, mari kita buat kesimpulan:
Kemas kini pengikatan sifat semua sub-komponen
Panggil OnChanges, OnInit, DoCheck, AfterContentInit cangkuk kitaran hayat semua sub-komponen
Kemas kini semasa DOM komponen
subkomponen mencetuskan pengesanan perubahan
memanggil cangkuk kitaran hayat AfterViewInit bagi semua subkomponen
Di sini kami tidak menumpukan pada butiran yang terlalu halus (jangan tertanya-tanya mengapa ia berada dalam susunan ini, cuma ingat bahawa ini adalah cara ia disediakan dalam Angular jika sesiapa ingin bercakap tentang Angular's). Reka bentuk di bahagian ini Jangan ragu untuk meninggalkan mesej di kawasan komen untuk membincangkan pemikiran anda~)
Dalam contoh pertama, ibu bapa komponen induk menghantar nama atribut input kepada anak komponen anak, dan komponen anak mengemas kini atribut nama komponen induk dalam ngOnInit Dalam erti kata lain, kod ini ** melanggar urutan pengesanan (** mengendalikan langkah pertama dalam langkah kedua urutan)!
<p>{{ name }}<p> <child [name]="name"></child>
Dalam contoh kedua, walaupun komponen anak turut mengemas kini atribut nama komponen induk dalam ngOnInit, tetapi kerana induk komponen induk tidak mengikat nama atribut input kepada komponen anak, ia tidak Akan ada situasi yang melanggar susunan baris gilir pengesanan perubahan, jadi ia boleh berjalan seperti biasa.
<p>{{ name }}<p> <child></child>
Pada masa ini, mari kita lihat jawapan yang sangat dipuji pada stackoverflow Ia akan menjadi lebih jelas mengikut urutan pengesanan di atas, kita akan mendapati bahawa selama ini kerana komponen induk mempunyai sepasang komponen anak Selepas pengikatan sifat dilakukan, tidak kira sama ada kod berikut dilaksanakan dalam mana-mana cangkuk kitaran hayat OnChanges, OnInit, DoCheck, AfterContentInit dan AfterViewInit, ralat akan dilaporkan.
this.parentCmpt.name = 'child'
Baiklah, sekarang kami telah memahami sebab sebenar mengapa ralat ini berlaku, tetapi saya masih ingin mengingatkan anda bahawa ralat ini hanya akan dicetuskan dalam persekitaran pembangunan dan akan dipanggil dalam persekitaran pengeluaranenableProdMode()
, bilangan pengesanan perubahan akan dikurangkan daripada 2 kepada 1. Bahagian ini juga diterangkan dalam Kod sumber sudut .
Sudah tentu anda tidak boleh memaksa penggunaan mod pengeluaran dalam persekitaran pembangunan hanya kerana pepijat ini...
ChangeDetectionStrategy
Lalai ialah Lalai, iaitu CD komponen induk akan mencetuskan CD komponen anak, tetapi jelas dalam beberapa kes kita boleh menilai sendiri bahawa sesetengah komponen anak akan tidak mencetuskan CD komponen induk Tidak perlu mencetuskan, tetapi OnPush
则是 Angular 为开发者提供的一便捷操作方式。
用动图来表示就是:查看链接
知名的 Angular 开源组件库 ng-zorro 就使用了大量的 OnPush 策略,这也是 Angular 性能优化的方法之一。
Angular 给每个组件都关联了一份组件视图,通过 ChangeDetectorRef
可以拿到相关联的视图,在定义中我们可以看到:
export declare abstract class ChangeDetectorRef { abstract checkNoChanges(): void; abstract detach(): void; abstract detectChanges(): void; abstract markForCheck(): void; abstract reattach(): void; }
观察下面的动图,被 detached
的组件将不会被检查变更。
而 reattach
则可以让被 detached
的组件重新可以被检测到变更。
reattach
只会重新启用对当前组件的变更检测,但是如果父组件没有启动变更检测,那么 reattach
并不会起作用,而 markForCheck
可以很好地解决这个问题。
这一点在 ng-zorro 的源码中可以了解一二。
例如在 nz-anchor 组件中更改 nz-anchor-link 组件的 active 属性时,由于本身 ChangeDetectionStrategy
为 OnPush
,那么就需要激活 markForCheck 来重新启用检测。具体写法可以查看 github 中的源代码。
用动图来展示则是这样,注意观察设置了 MFC 的前后变化
这个方法如同字面意思一样很好理解,就是触发一次变更检测啦,还记得本文中的第一个例子吗,我们不手动触发 tick()
,而是触发 detechtChanges()
也是可以达到效果的。
到这里,我相信大家已经基本弄明白了 Angular 变更检测,如果有任何疑问,欢迎在评论区交流讨论~
在撰写这篇文章时,笔者参(fu)考(zhi)了大量的社区文章和讨论,一方面是感慨如此重要的概念在 Angular 中文社区中却只有零星几篇相关介绍的文章,另一方面是看到了虽然国内 Angular 开发者虽然数量远少于 React 和 Vue,却依然非常热情的贡献自己的知识和见解来为 Angular 中文社区添砖加瓦,作为已使用 Angular 半年多的开发者,深深感受到 Google 的工程美学。
大而全且不失优雅,是笔者对 Angular 这款 Web 框架的最大感受,感谢开源社区中的各位开发者们~
对于文中描述错误的地方,还望大佬们批评斧正~
原文地址:https://juejin.cn/post/6844904079878012935
作者:LangWalker
更多编程相关知识,请访问:编程入门!!
Atas ialah kandungan terperinci Membawa anda untuk mengetahui lebih lanjut tentang pengesanan perubahan dalam Angular. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!