Angular中什么是變更檢測(cè)?下面本篇文章帶大家了解一下變更檢測(cè),并介紹一下什么情況下會(huì)引起變更檢測(cè),希望對(duì)大家有所幫助!

前端(vue)入門到精通課程,老師在線輔導(dǎo):聯(lián)系老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調(diào)試工具:點(diǎn)擊使用
什么是變更檢測(cè)?
簡(jiǎn)單來說,變更檢測(cè)就是Angular用來檢測(cè)視圖與模型之間綁定的值是否發(fā)生了改變,當(dāng)檢測(cè)到模型中的值發(fā)生改變時(shí),則同步到視圖上,反之,當(dāng)檢測(cè)到視圖上的值發(fā)生改變時(shí),則回調(diào)對(duì)應(yīng)的綁定函數(shù)。【相關(guān)教程推薦:《angular教程》】
也就是,把模型的變化和視圖保持一致的機(jī)制,這種機(jī)制,我們稱為變更檢測(cè)。

在Angular里,開發(fā)者無需把精力放到具體的DOM更新上,關(guān)注與業(yè)務(wù)就可以了,因?yàn)檫@部分工作Angular幫我們做了。
如果不用Angular的話,用原生的JS開發(fā),我們必須手動(dòng)的去更新DOM,先來看一個(gè)例子。
<html> <div id="dataDiv"></div> <button id="btn">updateData</button> <canvas id="canvas"></canvas> <script> let value = 'initialValue'; // initial rendering detectChange(); function renderHTML() { document.getElementById('dataDiv').innerText = value; } function detectChange() { const currentValue = document.getElementById('dataDiv').innerText; if (currentValue !== value) { renderHTML(); } } // Example 1: update data inside button click event handler document.getElementById('btn').addEventListener('click', () => { // update value value = 'button update value'; // call detectChange manually detectChange(); }); // Example 2: HTTP Request const xhr = new XMLHttpRequest(); xhr.addEventListener('load', function() { // get response from server value = this.responseText; // call detectChange manually detectChange(); }); xhr.open('GET', serverUrl); xhr.send(); // Example 3: setTimeout setTimeout(() => { // update value inside setTimeout callback value = 'timeout update value'; // call detectChange manually detectChange(); }, 100); // Example 4: Promise.then Promise.resolve('promise resolved a value').then(v => { // update value inside Promise thenCallback value = v; // call detectChange manually detectChange(); }, 100); // Example 5: some other asynchronous APIs document.getElementById('canvas').toBlob(blob => { // update value when blob data is created from the canvas value = `value updated by canvas, size is ${blob.size}`; // call detectChange manually detectChange(); }); </script> </html>
在上面的例子中,我們更新數(shù)據(jù)后,需要調(diào)用detectChange() 來檢查數(shù)據(jù)是否已更改。如果數(shù)據(jù)已經(jīng)更改,則渲染HTML以反應(yīng)更新的數(shù)據(jù)。當(dāng)然,在Angular中,開發(fā)者無需關(guān)心這些步驟,只需要更新你的數(shù)據(jù)就可以了,DOM會(huì)自動(dòng)更新。這就是變更檢測(cè)。
什么情況下會(huì)引起變更檢測(cè)
變更檢測(cè)的關(guān)鍵在于如何最小粒度地檢測(cè)到綁定的值是否發(fā)生了改變,那么在什么情況下會(huì)導(dǎo)致這些綁定的值發(fā)生變化呢?
結(jié)合日常開發(fā),來看幾種場(chǎng)景。
場(chǎng)景一
組件初始化:
當(dāng)啟動(dòng) Angular 應(yīng)用程序時(shí),Angular 會(huì)加載引導(dǎo)組件并觸發(fā) ApplicationRef.tick() 來調(diào)用變更檢測(cè)和視圖渲染。
場(chǎng)景二
DOM和BOM事件:
DOM 事件或BOM事件偵聽器可以更新 Angular 組件中的數(shù)據(jù),還可以觸發(fā)變更檢測(cè),如下例所示。
@Component({ selector: "counter", template: ` Count:{{ count }} <br /> <button (click)="add()">Add</button> `, }) export class CounterComponent { count = 0; constructor() {} add() { this.count = this.count + 1; } }
我們?cè)谝晥D上通過插值表達(dá)式綁定了counter中的count屬性,當(dāng)點(diǎn)擊按鈕時(shí),改變了count屬性的值,這時(shí)就導(dǎo)致了綁定的值發(fā)生了變化。
場(chǎng)景三
HTTP數(shù)據(jù)請(qǐng)求:
@Component({ selector: "todos", template: ` <li *ngFor="let item of todos">{{ item.titme }}</li> `, }) export class TodosComponent implements OnInit { public todos: TodoItem[] = []; constructor(private http: HttpClient) {} ngOnInit() { this.http.get<TodoItem[]>("/api/todos").subscribe((todos: TodoItem[]) => { this.todos = todos; }); } }
我們?cè)趖odos這個(gè)組件里向服務(wù)端發(fā)送了一個(gè)Ajax請(qǐng)求,當(dāng)請(qǐng)求返回結(jié)果時(shí),會(huì)改變視圖中綁定的todos的值。
場(chǎng)景四
其他宏任務(wù)和微任務(wù):
比如 setTimeout() 或 setInterval()。你還可以在 setTimeout() macroTask 的回調(diào)函數(shù)中更新數(shù)據(jù)。
@Component({ selector: 'app-root', template: '<div>{{data}}</div>'; }) export class AppComponent implements OnInit { data = 'initial value'; ngOnInit() { setTimeout(() => { // user does not need to trigger change detection manually this.data = 'value updated'; }); } }
實(shí)際開發(fā)中可能會(huì)在某一個(gè)函數(shù)里調(diào)用定時(shí)器去改變一個(gè)綁定的值。
再比如 Promise.then() 。其他異步 API(比如 fetch)會(huì)返回 Promise 對(duì)象,因此 then() 回調(diào)函數(shù)也可以更新數(shù)據(jù)。
@Component({ selector: 'app-root', template: '<div>{{data}}</div>'; }) export class AppComponent implements OnInit { data = 'initial value'; ngOnInit() { Promise.resolve(1).then(v => { // user does not need to trigger change detection manually this.data = v; }); } }
場(chǎng)景五
其他異步操作:
除了 addEventListener(),setTimeout() 和 Promise.then() ,還有其他一些操作可以異步更新數(shù)據(jù)。比如 WebSocket.onmessage() 和 Canvas.toBlob() 。
不難發(fā)現(xiàn),上述幾種情況都有一個(gè)共同點(diǎn),就是導(dǎo)致綁定值發(fā)生改變的事件都是 異步事件。只要發(fā)生了異步操作,Angular就會(huì)認(rèn)為有狀態(tài)可能發(fā)生了變化,然后進(jìn)行變更檢測(cè)。
思考:還有哪些是異步事件啊?
這些包含了應(yīng)用程序可能會(huì)在其中更改數(shù)據(jù)的最常見的場(chǎng)景。只要Angular檢測(cè)到數(shù)據(jù)可能已更改,就會(huì)進(jìn)行變更檢測(cè),變更檢測(cè)的結(jié)果是根據(jù)這些新數(shù)據(jù)DOM被更新。Angular 會(huì)以不同的方式檢測(cè)變化。對(duì)于組件初始化,Angular 調(diào)用顯式變更檢測(cè)。對(duì)于異步操作,Angular 會(huì)使用 Zone 在數(shù)據(jù)可能被修改的地方檢測(cè)變化,并自動(dòng)運(yùn)行變更檢測(cè)。
那如何訂閱這些異步事件呢?請(qǐng)期待下一篇哦。
站長(zhǎng)資訊網(wǎng)