CHANGE DETECTION IN ANGULAR 2
In this article I will talk in depth about the Angular 2 change detection system.
HIGH-LEVEL OVERVIEW
An Angular 2 application is a tree of components.

An Angular 2 application is a reactive system, with change detection being the core of it.

Every component gets a change detector responsible for checking the bindings defined in its template. Examples of bindings:{{todo.text}} and [todo]=”t”. Change detectors propagate bindings[c] from the root to leaves in the depth first order.
In Angular 2 there are no two-way data-bindings. That is why the change detection graph is a directed tree and cannot have cycles (i.e., it is an arborescence). This makes the system significantly more performant. And what is more important we gain guarantees that make the system more predictable and easier to reason about. How Fast Is It?
By default the change detection goes through every node of the tree to see if it changed, and it does it on every browser event. Although it may seem terribly inefficient, the Angular 2 change detection system can go through hundreds of thousands of simple checks (the number are platform dependent) in a few milliseconds. How we managed to achieve such an impressive result is a topic for another blog post.
Angular has to be conservative and run all the checks every single time because the JavaScript language does not give us object mutation guarantees. But we may know that certain properties hold if we, for example, use immutable or observable objects. Previously Angular could not take advantage of this, now it will.
IMMUTABLE OBJECTS
If a component depends only on its bindings, and the bindings are immutable, then this component can change if and only if one of its bindings changes. Therefore, we can skip the component’s subtree in the change detection tree until such an event occurs. When it happens, we can check the subtree once, and then disable it until the next change (gray boxes indicate disabled change detectors).

If we are aggressive about using immutable objects, a big chunk of the change detection tree will be disabled most of the time.

Implementing this is trivial.
class ImmutableTodoCmp {
todo:Todo;
constructor(private bingings:BindingPropagationConfig){}
// onChange is a part of the component’s lifecycle.
// It is called when any the bindings changes.
onChange(_) => bingings.shouldBePropagated();
}
The framework can make it even easier to use through a mixin.
class ImmutableTodoCmp {
todo:Todo;
}
applyMixins(ImmutableTodoCmp, [ComponentWithImmutableBindings]);
OBSERVABLE OBJECTS
If a component depends only on its bindings, and the bindings are observable, then this component can change if and only if one of its bindings emits an event. Therefore, we can skip the component’s subtree in the change detection tree until such an event occurs. When it happens, we can check the subtree once, and then disable it until the next change.
Although it may sound similar to the Immutable Objects case, it is quite different. If you have a tree of components with immutable bindings, a change has to go through all the components starting from the root. This is not the case when dealing with observables.
Let me sketch out a small example demonstrating the issue.
type ObservableTodo = Observable<Todo>;
type ObservableTodos = Observable<Array<ObservableTodo>>;
@Component({selector:’todos’})
class ObservableTodosCmp {
todos:ObservableTodos;
//...
}
The template of ObservableTodosCmp:
<todo template=”ng-repeat: var t in todos” todo=”t”></todo>
Finally, ObservableTodoCmp:
@Component({selector:’todo’})
class ObservableTodoCmp {
todo:ObservableTodo;
//...
}
As you can see, here the Todos component has only a reference to an observable of an array of todos. So it cannot see the changes in individual todos.
The way to handle it is to check the path from the root to the changed Todo component when its todo observable fires an event. The change detection system will make sure this happens.
Say our application uses only observable objects. When it boots, Angular will check all the objects.

So the state after the first pass will look as follows.

Let’s say the first todo observable fires an event. The system will switch to the following state:

And after checking App_ChangeDetector, Todos_ChangeDetector, and the first Todo_ChangeDetector, it will go back to this state.

Assuming that changes happen rarely and the components form a balanced tree, using observables changes the complexity of change detection from O(N) to O(logN), where N is the number of bindings in the system.
Angular will come with mixins for the most popular libraries and Object.observe.
class ObservableTodoCmp {
todo:ObservableTodo;
}
applyMixins(ImmutableTodoCmp, [ComponentWithRxObservableBindings]);
But this capability is not tied to those libraries. Implementing such a mixin for another library should be a matter of a few lines of code.
DO OBSERVABLES CAUSE CASCADING UPDATES?
Observable objects have bad reputation because they can cause cascading updates. Anyone who has experience in building large applications in a framework that relies on observable models knows what I am talking about. One observable object update can cause a bunch of other observable objects trigger updates, which can do the same. Somewhere along the way views get updated. Such systems are very hard to reason about.
Using observable objects in Angular 2 as shown above will not have this problem. An event triggered by an observable just marks a path from the component to the root as to be checked next time. Then the normal change detection process kicks in and goes through the nodes of the tree in the depth first order. So the order of updates does not change whether you use observables or not. This is very important. Using an observable object becomes a simple optimization that does not change the way you think about the system.
DO I HAVE TO USE OBSERVABLE/IMMUTABLE OBJECTS EVERYWHERE TO SEE THE BENEFITS?
No, you don’t have to. You can use observables in one part of your app (e.g., in some gigantic table.), and that part will get the performance benefits. Even more, you can compose different types of components and get the benefits of all of them. For instance, an “observable component” can contain an “immutable component”, which can itself contain an “observable component”. Even in such a case the change detection system will minimize the number of checks required to propagate changes.
NO SPECIAL CASES
Support for immutable and observable objects is not baked into the change detection. These types of components are not in any way special. So you can write your own directives that use change detection in a “smart” way. For instance, imagine a directive updating its content every N seconds.
SUMMARY
- An Angular 2 application is a reactive system.
- The change detection system propagates bindings from the root to leaves.
- Unlike Angular 1.x, the change detection graph is a directed tree. As a result, the system is more performant and predictable.
- By default, the change detection system walks the whole tree. But if you use immutable objects or observables, you can take advantage of them and check parts of the tree only if they “really change”.
- These optimizations compose and do not break the guarantees the change detection provides.
API CHANGES
This described functionality is already in the Angular 2 master branch on GitHub. The current API, however, may change before the first stable release of the framework.
-
Victor Savkin Mod Sebastian Sebald • 2 months agoAngular will not force an architecture on you, but the new change detection and the Forms API, which I will write about in detail soon, make Flux a good option.
Btw, you can already build Angular 1.x apps using Flux http://victorsavkin.com/post/9....
Ole-André Johansen Victor Savkin • 2 months agoAngular 2 doesn't come with any architecture strings attached? Can you clearify?
Foo • 2 months agoInteresting stuff, thanks! One question: how exactly do observables avoid cascading updates? My understanding is that in Angular 1.x, cascading updates are dealt with by repeating the $digest() loop until no further changes are detected. Won't that still be true? Thanks to the new immutable and observable features you outline, each loop will have less to process, but it still needs to repeat until a stable state is reached, right?
Victor Savkin Mod Foo • 2 months agoThanks.
In Angular2 we walk the change detection graph only once (TTL = 1). This is possible because the graph does not have any cycles.
What I meant by cascading updates is the following:
Say we have three observable objects: ObjectA, ObjectB, ObjectC. Consider the following situation.
- ObjectA fires an event
- The view rendering ObjectA catches the event and rerenders
- ObjectB catches the event and fires its own event
- The view rendering ObjectB catches the event and rerenders
- ObjectC catches the event and fires its own event
- ObjectA catches the event fired by ObjectC
...Note how the framework calls (view.render) are interleaved with the events. It is hard to tell what gets rerendered when. This is a real problem of many front-end frameworks.
In Angular2 it works as follows.
- ObjectA fires an event
- ObjectB catches the event and fires its own event
- ObjectC catches the event and fires its own event
- ObjectA catches the event fired by ObjectCWhile it is happening the framework is marking the parts of the change detection graph that are updated. This marking has no observable side effects. At the end of the VM turn the framework will check only the marked paths and update the bindings.
Note that there is a clear separation of when the model is updated and when the framework does its magic. The bindings would be updated in the same order if ObjectA, ObjectB, and ObjectC were not observable. This is very important.
Csaba Tamas • 15 days agoHow can I manual run change detection or subscripe it for example in component.js
this.service.ajaxCall((result) => {
this.todos = result.todos; //change
this.findNewElementInDOM(); // dont't work
--> Don't runned the change detection here, but I only can here cach the async call and detect change
});
--> change detection only run after ajaxCall callback executed
Manfred Steyer • a month agoI'm wondering, when the digest-phase is triggered. You mentioned that it's triggered on every browser-event. But I've noticed, that the view is even updated, when I update the bindings in an async success-handler, angular2 isn't aware of. As I don't use observables this seems quite magic to me ...
Manfred Steyer Manfred Steyer • a month agoI've found the answer to my question: zone.js creates hooks for events ...
NG-newbie Manfred Steyer • a month agoCould you point to the code where this happens? I was also asking myself similar question.
Manfred Steyer NG-newbie • a month agoSure. Have a look here: https://github.com/btford/zone...
Zone.js rewrites the properties of JavaScript-prototypes to get notified, when an event happens ...
seba • a month agoSo, how does it differ from React? It looks to be almost the same now... Well, except they've invented their own language now, Hooray :( Sure you can do it in plain JS, but then you end up with the same mess as in Angular 1. Moving stuff out of your api and into annotations, doesn't make your api better.
It seems angular 2 will loose a huge amount of convenience for the developer in trade for performance, while the angular folks been preaching angular 1 didn't have a performance problem because you never need to show more than 2000 bound items at once etc. And to be honest, angular 1 is performing just fine and I'd rather keep my speed of development than get performance I don't need. If people need it, let them use React. Now we seem to loose the choice and get 2 times React.
Manfred Steyer seba • a month agoWhile I see this point just like you, I hope, that there will be some syntax sugar, that will bring back the convenience from 1.x to 2.x ...
kowdermeister • a month agoIt seems it's safe to conclude that Angular apps are not written anymore in JavaScript, but in Angular language. Probably this will never make it popular.
Jimmy Breck-McKye • 2 months agoForgive me, but didn't Knockout.js effectively implement this four years ago?
Victor Savkin Mod Jimmy Breck-McKye • 2 months agoIf you are referring to the notion of Observables, then, yes, most frameworks support observable models. Most frameworks, however, require you to use a particular kind of observables and suffer from cascading updates.
Angular does not force you to use one kind of observables: you can use rxjs, object.observe, backbone models, probably even knockout models. It can take advantage of any of them because the described mechanism is more generic.
The most important thing is that you don't have to use observables at all and instead take advantage of immutable objects. The framework remains model agnostic.
Jimmy Breck-McKye Victor Savkin • 2 months agoKnockout does not require you to use observables if a model property does not mutate; it will quite happily bind plain properties - it just won't react to mutations. You can even place computed properties in front of multiple observables, and Knockout will only update the computed's subscribers when the computed's result actually changes.
Knockout provides a great deal of fine control over how mutation propagates; the utils it provides make it easy to write performant code naively. I think it's a real shame that so many developers dismiss it without even looking at it.
johnpapa7 Victor Savkin • 2 months agoThis is an important statement here: "The most important thing is that you don't have to use observables at all and instead take advantage of immutable objects."
One of the biggest draws to Angular 1.x was the idea of not requiring an implementation of wrapping objects with observability. We could use raw javascript objects. Anyone who has done this in Knockout or other similar observable tech (IObservable in .NET even) knows the cost of it is you always have to convert your objects (or wrap them) with this feature. Can you clarify your statement here on how immutable objects can be used, say, given a todo:
[
{ id: 1, description: 'go shopping'},
{id: 2, description: 'take kids to school'}
]
Victor Savkin Mod johnpapa7 • 2 months agoThere are three problems with using immutable objects in Angular 1.x:
- Angular does not know that they are immutable and keeps checking them. So it is not efficient.
- Custom immutable collections do not work with NgRepeat out of the box .
- NgModel does not play nicely with immutable objects.Angular2 solves all of them.
- The change detection gives you a mechanism to express that the component depends only on immutable objects and, therefore, should not be checked until one of the bindings gets updated, as follows:
// There will be a way to express it declaratively
class ImmutableTodoCmp {
todo:Todo;
constructor(private bingings:BindingPropagationConfig){}
onChange(_) => bingings.shouldBePropagated();
}- The change detection is pluggable, so you can teach it to detect changes in any collection.
- The new Forms API is immutable object friendly.In Angular2 using immutable objects feels natural. You can pass an immutable collection to a repeater.
<todo !foreach="var t in todos" [todo]="t">
Use an immutable object in your template
{{todo.description}}
Even though Angular2 "just works", you will have to change the way your app is architected if you make most of your models immutable. This is not Angular specific. This will be true in any framework. That is why there are such things as Flux and Cursors (https://github.com/omcljs/om/w....
johnpapa7 Victor Savkin • 2 months agoIt appears that json objects will have to be converted to an object of this type and cannot be used as is. Unless I misunderstand. Right?
We may gain Perf but we lose something big there.
Victor Savkin Mod johnpapa7 • 2 months agoSorry, I was not clear. We can define Todo in TypeScript as follows:
interface Todo {
description:string;
checked:boolean;
}So Todo just defines the shape of the object. It can be a regular JSON object with the two fields.
Sekib Omazic • 2 months agoWill A2 apply DOM changes all at once (batch update) like ReactJS? I couldn't find something like "task queue" in the code base.
Sekib Omazic • 2 months agoSo to use immutable objects I have to inform angular2 about it by implementing onChange method in the component? And if I want to use observables I'd have to use objects of type Observable?
A working TodoApp would help better understand the change detection in A2.
Victor Savkin Mod Sekib Omazic • 2 months ago>> So to use immutable objects I have to inform angular2 about it by implementing onChange method in the component?
You can use immutable and observable objects without telling Angular about it, but then you won't get any performance benefits out of it. To get the performance benefits you need to tell the framework that you depend only on immutable or observable objects.
>> And if I want to use observables I'd have to use objects of type Observable?
You won't have to use any special Observable class. Any push-based object can be used here (e.g., Object.observe or Rx observables). The framework does not make any assumptions about the type of your observables. Likewise, the framework does not make any assumptions about what is immutable.
>> A working TodoApp would help better understand the change detection in A2.
I am putting something together that will show advanced scenarios of using the change detection.
Badru Victor Savkin • 2 months agoWaiting for that "something together" victor. It will help to understand better.
One more question, the above syntax is not native js. Is it AtScript syntax?
CHANGE DETECTION IN ANGULAR 2的更多相关文章
- angular 2 - 006 change detection 脏治检查 - DC
ANGULAR CHANGE DETECTION EXPLAINED 引发脏治检查有三种方式: Events - click, submit, - XHR - Fetching data from a ...
- [Angular & Unit Testing] Automatic change detection
When you testing Component rendering, you often needs to call: fixture.detectChanges(); For example: ...
- [Audio processing] Harmonic change detection function (HCDF)
Harmonic change detection function (HCDF) 是根据 Tonal Centroid (TC)实现的,首先TC如何提取? Step 1. 提取PCP特征 Step ...
- [Angular] Angular Custom Change Detection with ChangeDetectorRef
Each component has its own ChangeDetectorRef, and we can inject ChangeDetectorRef into constructor: ...
- Angular中Constructor 和 ngOnInit 的本质区别
在Medium看到一篇Angular的文章,深入对比了 Constructor 和 ngOnInit 的不同,受益匪浅,于是搬过来让更多的前端小伙伴看到,翻译不得当之处还请斧正. 本文出处:The e ...
- TWO PHASES OF ANGULAR 2 APPLICATIONS
Angular 2 separates updating the application model and reflecting the state of the model in the view ...
- Angular 4+ 修仙之路
Angular 4.x 快速入门 Angular 4 快速入门 涉及 Angular 简介.环境搭建.插件表达式.自定义组件.表单模块.Http 模块等 Angular 4 基础教程 涉及 Angul ...
- 来自 Thoughtram 的 Angular 2 系列资料
Angular 2 已经正式 Release 了,Thoughtram 已经发布了一系列的文档,对 Angular 2 的各个方面进行深入的阐释和说明. 我计划逐渐将这个系列翻译出来,以便对大家学习 ...
- [Angular 2] How To Debug An Angular 2 Application - Debugging via Augury or the Console
In this lesson we will learn several ways to debug an Angular 2 application, including by using Augu ...
随机推荐
- 初识安卓小程序(Android短信发送器)
首先,先创建一个安卓项目(我的版本号是4.4.2的),名字为"短信发送器" 然后在res目录下找到layout目录,找到activity_main.xml或fragment_mai ...
- Hive之 hive架构
Hive架构图 主要分为以下几个部分: 用户接口,包括 命令行CLI,Client,Web界面WUI,JDBC/ODBC接口等 中间件:包括thrift接口和JDBC/ODBC的服务端,用于整合Hiv ...
- js的拼接
var datatr = " <tr>"; datatr += "<td bgcolor='#EEEEEE'><input class='i ...
- Windows应用程序的VC链接器设置
Windows应用程序的VC链接器设置 /*转载请注明出自 听风独奏 www.GbcDbj.com */ Windows应用程序分为GUI(Graphical User Interface)和CUI( ...
- hadoop启动时,报ssh: Could not resolve hostname xxx: Name or service not known
本文转载自:http://blog.csdn.net/wodewutai17quiet/article/details/76795951 问题:hadoop启动时,报ssh: Could not re ...
- bzoj1215 24点游戏
Description 为了培养小孩的计算能力,大人们经常给小孩玩这样的游戏:从1付扑克牌中任意抽出4张扑克,要小孩用“+”.“-”.“×”.“÷”和括号组成一个合法的表达式,并使表达式的值为24点. ...
- 分类预测输出precision,recall,accuracy,auc和tp,tn,fp,fn矩阵
此次我做的实验是二分类问题,输出precision,recall,accuracy,auc # -*- coding: utf-8 -*- #from sklearn.neighbors import ...
- Esxi5-管理平台vcenter5.0_数据库迁移流程
migrating-vcenter-database-express-to-sql-2008-r2 一. 准备环境. ESXi5.0主机 IP:192.168.1.158 ...
- ACM刷题踩坑记录
2017-12-26: 1.再次被写法坑了好长一会,调了半天的bug,还是没找出来.最后,发现,又坑在这个小细节上了.这样子写,第一个if和第三个else在一次循环中都会执行,然后,就GG了. 要注意 ...
- 并发包学习(三)-AbstractQueuedSynchronizer总结
J.U.C学习的第二篇AQS.AQS在Java并发包中的重要性,毋庸置疑,所以单独拿出来理一理.本文参考总结自<Java并发编程的艺术>第五章第二节队列同步器. 什么是AbstractQu ...