什么是变更检测?
简单来说,变更检测就是Angular用来检测视图与模型之间绑定的值是否发生了改变,当检测到模型中的值发生改变时,则同步到视图上,反之,当检测到视图上的值发生改变时,则回调对应的绑定函数。【相关教程推荐:《angular教程》】
也就是,把模型的变化和视图保持一致的机制,这种机制,我们称为变更检测。
(资料图片)
在Angular里,开发者无需把精力放到具体的DOM更新上,关注与业务就可以了,因为这部分工作Angular帮我们做了。
如果不用Angular的话,用原生的JS开发,我们必须手动的去更新DOM,先来看一个例子。
<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>
登录后复制
在上面的例子中,我们更新数据后,需要调用detectChange()来检查数据是否已更改。如果数据已经更改,则渲染HTML以反应更新的数据。当然,在Angular中,开发者无需关心这些步骤,只需要更新你的数据就可以了,DOM会自动更新。这就是变更检测。
什么情况下会引起变更检测
变更检测的关键在于如何最小粒度地检测到绑定的值是否发生了改变,那么在什么情况下会导致这些绑定的值发生变化呢?
结合日常开发,来看几种场景。
场景一
组件初始化:
当启动 Angular 应用程序时,Angular 会加载引导组件并触发 ApplicationRef.tick() 来调用变更检测和视图渲染。
场景二
DOM和BOM事件:
DOM 事件或BOM事件侦听器可以更新 Angular 组件中的数据,还可以触发变更检测,如下例所示。
@Component({ selector: "counter", template: ` Count:{{ count }}
`,})export class CounterComponent { count = 0; constructor() {} add() { this.count = this.count + 1; }}
登录后复制
我们在视图上通过插值表达式绑定了counter中的count属性,当点击按钮时,改变了count属性的值,这时就导致了绑定的值发生了变化。
场景三
HTTP数据请求:
@Component({ selector: "todos", template: `
{{ item.titme }} `, }) export class TodosComponent implements OnInit { public todos: TodoItem[] = []; constructor(private http: HttpClient) {} ngOnInit() { this.http.get("/api/todos").subscribe((todos: TodoItem[]) => { this.todos = todos; }); } }登录后复制
我们在todos这个组件里向服务端发送了一个Ajax请求,当请求返回结果时,会改变视图中绑定的todos的值。
场景四
其他宏任务和微任务:
比如 setTimeout() 或 setInterval()。你还可以在 setTimeout() macroTask 的回调函数中更新数据。
@Component({ selector: "app-root", template: "{{data}}";})export class AppComponent implements OnInit { data = "initial value"; ngOnInit() { setTimeout(() => { // user does not need to trigger change detection manually this.data = "value updated"; }); }}
登录后复制
实际开发中可能会在某一个函数里调用定时器去改变一个绑定的值。
再比如 Promise.then()。其他异步 API(比如 fetch)会返回 Promise对象,因此 then() 回调函数也可以更新数据。
@Component({ selector: "app-root", template: "{{data}}";})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; }); }}
登录后复制
场景五
其他异步操作:
除了 addEventListener(),setTimeout() 和 Promise.then(),还有其他一些操作可以异步更新数据。比如 WebSocket.onmessage()和 Canvas.toBlob()。
不难发现,上述几种情况都有一个共同点,就是导致绑定值发生改变的事件都是异步事件。只要发生了异步操作,Angular就会认为有状态可能发生了变化,然后进行变更检测。
思考:还有哪些是异步事件啊?
这些包含了应用程序可能会在其中更改数据的最常见的场景。只要Angular检测到数据可能已更改,就会进行变更检测,变更检测的结果是根据这些新数据DOM被更新。Angular 会以不同的方式检测变化。对于组件初始化,Angular 调用显式变更检测。对于异步操作,Angular 会使用 Zone 在数据可能被修改的地方检测变化,并自动运行变更检测。
那如何订阅这些异步事件呢?请期待下一篇哦。
更多编程相关知识,请访问:编程教学!!
以上就是Angular中什么是变更检测?什么情况下会引起变更检测?的详细内容,更多请关注php中文网其它相关文章!