Optimize and debug change detection like a pro | Max Koretskyi | AngularConnect 2018

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] okay how are you doing today ready for some really really deep stuff you know I've been wanting to give this talk for almost a year now I submitted it to ng-conf to angular up to other conferences along with other talks and they always chose different talks you know maybe they thought this one is very very to deep dive but finally I have a chance to deliver it here at angular connect so really happy about that now my name is max I most of you some of you know me as ng wizard I've recently been upgraded to wizard of the web and I'm known to reverse-engineer frameworks and as I do that I try to give away the secrets that are inside these frameworks and I do that to inspire you all to become better developers so I've spent a lot of time reverse engineering I think I qualify as reverse engineering edit if I know if there is such thing and this one topic that fascinates me the most which is change detection all right it's very mysterious topic and angle there are a lot of things involved in that and today we're going to look at the internals and you'll know how it works you know I guess a lot of people coming in so that's one I'm smiling okay so what is change detection basically change detection in general it's the mechanism designed to track changes in the application state and render the updated state on the screen right and what in web applications are interactive right user can click on a button and the states changes so we need to detect that and update the screen right so that's the purpose of change detection in general and it's the core of most frameworks react angular in all frameworks implemented differently so why do you need to know how exactly change detection works in angular right because um most of the style most of the time change detection just sits there quietly inside angular and just works right we don't need to know how it works or what it does but once in a while things go awry and it causes errors performance issues and even confusions sorry guys familiar with this error yeah I bet you are this one I think tops the list of the most confusing errors in angular some developers even think that it's a bug I've seen a few github issue stuff request the fix well it's not a bug there's a purpose for this error and today we'll learn why we sometimes get it also as you know change detection in angular runs over the entire tree of components I would take some time and it runs synchronously and if it runs too often it is it may cause delays or even unresponsive applications right so performance again is the area where the knowledge of change detection internals can help you write because you'll be able to pinpoint the areas of your application that cause excessive change detection runs and optimize them okay now before we dive in just a few words about myself I already told you about my addiction I really like to live on the edge I do we have risk takers in the audience today just raise your hand okay all right well I think how many people raise their hands but I think we are always takers because we take our chances every day with JavaScript right rune I work so I also like to walk on railroad tracks somewhere in the middle of my travel and I managed to become a Google directs pert and received the MVP award and I was so blown away by how good Asia grid was here and the team behind it that I decided decided to join them as a developer advocate so that's where I work okay also most of my free time goes to angular in doubts how many of you know about angular in depth all a lot more hands yeah I'm really happy about yeah well this is the place where I write about angular internals and the architecture of angular applications and I also inspired the awesome community of writers who helped me propel this resource okay so finally we're ready to dive in and we're gonna start with a simple widget so they did here this component when we click on the button will show you the time when change detection happens in angular right because when you click on the button it triggers change detection so we're going to see a screen updated and here's what the implementation looks like for this component right just notice how simple it is we only have one our setter or surrogate or name time and we bind it to the spawn element through the text content binding right so we want to display that tags in the spawn and now if I run this just you can see that the screen being updated I'm gonna click on the button okay see the screens been updated but then I open a console and I will see this now okay and I'll write the error expression changed after it was chat well we certainly didn't expect it there because we have such a simple functionality right just one getter and one binding right we usually get this error when we have complex hierarchy is a lot of updates this is just one getter okay so how's it possible that we received it well no worries this is about this what we're about to investigate and we'll start with the error message so this is the binding related to the earth and what the error tells us is that basically it evaluated expression that we provided for the tax content and it detected the difference right indeed there is a difference one millisecond between the values okay now why did they in Goa do that why did it evaluate it twice instead of just once right and when exactly during change detection did it happen so these are the questions that spark my interest originally and eventually led me down to the internals of change detection right because to find answers to these questions I had to read the sources and debug and debug and I can say that I debug for a few months is really because you won't find this explanation on the web so I had to do that on my own and I've just covered a lot of a lot of interests and things inside angular so today I want to share some of them with you and let's start with this it's a template right every component in angular has a template with HTML okay with HTML elements so when angular creates an instance of a component it needs to create Dom notes for these HTML elements right and there's got to be a place for angular to put this reference into because when a component is destroyed what we want to do we want to remove these Dom nodes from the document right so there's got to be a place also angular creates an instance of a component class right also there's a reference to it so it needs to be stored somewhere and in fact in angular there is a data structure internally specifically for that purpose it's called a view so one thing to remember from this talk is that every component in angular under the hood is represented as a view there is one-to-one relationship okay then as a compiler goes through the template it tries to identify properties of dom element that needs to be updated during change detection right and in our case this is text content property for each such property indoor creates something called binding okay and the binding is a data structure that defines two things what we need to update during change detection and where to get value from right and it's an expression that you specify in the template and if you have many bindings usually you have a lot of bindings in a template you will have each binding created for each site Association so view created for a component in a set of bindings created for that components template the main building blocks of change detection in angular okay now here's how they are used so when angular runs a change detection for if you so I'm seeing for a view but you can hear for a component right because I just told you that this one-to-one relationship but internally angular works with views okay so when angular on change detection for a view or we can say charts the view it runs over all bindings created for that component and evaluates expressions compares the result of the expressions to the previous values okay of that expressions again there is the property called old values on the view where angular puts these old results so it can compare them and this is what is known as dirty checking okay so it runs over bindings compares the results and if it detects the difference it updates the Dom okay so that's the basic mechanism of change detection and we'll see you later I'll show you this view and these bindings you will and the old values you'll be able to see it in runtime so let's get back to our error that we started with we only have one binding to text content property right so supposing gallons changed it action for this component evaluates the expression basically just reads the time from the component okay so it compares it to the previous value suppose it detects the difference and it updates the Dom right and also puts the current value to the old values array now what's interesting is that right after that synchronously angular runs an extra check to ensure that the expressions that it evaluated during change detection returned the same result okay this is this happens only in the development mode and we'll learn a bit later why angular does it but right now I'm trying to explain you the mechanism okay so and if the expressions produce different results then basically this check performs exactly the same steps as change detection runs over bindings evaluates compares but if it detects the difference its throws the error okay so what happened in our case is that basically we have date now here right that returns the current time step with millisecond precision so when angular evaluated this time it produced one result then probably change detection took more than one millisecond to run across all the tree of components or you know case just one component and then it it again this time which did now produce different results right we saw this one millisecond difference and it threw out the error how do we fix it right notice that I told you that angular runs this check synchronously okay right after change detection so if we update this value asynchronously we will avoid the error make sense okay so what I'm gonna do I'm gonna move the update logic devaluation logic out of the time property right just stored as a private variable on the component and now I need to update it this property asynchronously so I will use an async function that we have in JavaScript which is set interval okay and since we always want to have the current time with one millisecond precision using here one millisecond delay for the set interval okay so what run every one millisecond will execute the callback that will update private property time right and when angular runs change detection I will just read the latest update okay that's the main idea and this is a good solution and it would work if not for one thing who knows what is the reason it won't work okay well set interval in angular triggers change detection so if it runs continuously every one millisecond we're going to end up with an infinite loop of change detection runs okay so we need to run this set interval but not trigger change detection right in that case it would work so how can we do that and why the set interval triggers change detection in angular well it's because of the thing called the library called zone GS and I guess you've old familiar with that right so just a few words about some GS I want you to know that maybe you are you know that but contrary to popular belief some GS is not part of change detection mechanism in angular it's a standalone third-party library angular uses it to get notifications about asynchronous events right like in our case it's a set interval that notifies angular yet the framework angular can work without Sanji right it's just in that case you won't get notifications about that interval and other synchronous amounts but it can really well work without it now regarding don't yes we can have multiple zones on a webpage right zone provides an API to create different zones in angular only get sent if occasions about asynchronous events that are triggered within ng zone this is the zone that angular itself creates when it bootstraps so and all your applications code usually runs within that in jizan but you can run code outside of angular zone for example in zone a and so GS provides API to do that so and this is exactly what we need right we need to run set interval update private property but not notify angular right and notification means no change detection so that is the solution that we need okay so getting back to this code where we update the value asynchronously what I'm gonna do I'm gonna inject in G zone now and just wrap it in the round outside angular method okay that's a simple fix so in this case what we're doing is we're are updating private property time asynchronously okay which means that the synchronous check that follows change detection won't detect the difference right we update value asynchronous and to avoid change detection we run this code outside of angular zone okay now this is a very common optimization technique if you want to run some heavy computational code and want to avoid change detection rounds just execute your code outside of angular zone okay now let's summarize what we've learned and we've learned already quite a lot so every component and angle is represented as a view under the hood we have a bunch of bindings created by the compiler during change detection and Gila runs over these bindings evaluates expressions compares them and updates the Darmouth necessary and right after that in the development mode and go-arounds the synchronous check and compares the result and if it detects the difference it updates the down okay now you might be wondering okay max this view these bindings this dumb notes references all pretty abstract is there any way we can see them all right and I told you that I would show you so I spent a lot of time debugging applications you know so I know where I need to put debugger in the sources to figure out what's going on and this function check and update to you is the one function you need to know and this is where you need to put the bar where I put the barger often when I do Bach change detection so let me show it to you so this is our code right our application I'm going to open console now in this function is in the core module so I will find it now in the core module okay we're gonna wait till I do that so once I find it I'll put a breakpoint here okay and trigger change detection so I'll click on the button to trigger change detection and here's the view you see created for our component this is the instance of the component you see then these are the nodes the references to Dom nodes created for the template here's for example span element node and also old values right where angular keeps the results of the expressions from previous evaluations this is the result of the last evaluate expression for the binding okay so I encourage you to put it breakpoint to find it function put a breakpoint there and just play with it a little bit you will see how many what operations angular performs for a view or explore these data structures actually very very interesting okay I want to talk a little bit more about this error in the context of something called unidirectional data flow I also assume that most of you have read articles about unidirectional data flow why it's important how it's different to angularjs I want to talk again about it now so what is it exactly every application every angular application has two phases the first phase is updating the application State or component state right and it happens as a result of some callback invocation for example user click on the button your callback is executed you updated one component and then maybe through a shared service you've updated other components as well so the second phase is rendering basically taking that state and projecting it into something we can see on the screen and you as a user is responsible or as a developer is responsible for updating the state registering callbacks performing business logic but angular as a framework is responsible for rendering that state okay and it does does it through the mechanism of change detection but there is one important limitation of change detection as soon as angular checked one view or one component and moved to the child components you can no longer update the properties of the component that are used in the bindings right because during the synchronous check and gala will reevaluate the expression I will detect the difference okay you can still however update other properties on a component that are not used in bindings so this is the restriction imposed by the unidirectional data flow and this is why angular has this check to ensure that state hasn't changed now what's also important is that unidirectional data flow I'm talking about in terms of change detection is related to this presentation layer because you also may have heard about unidirectional data flow imposed by state management libraries like ng rx right we go through one flow so these are two different unidirectional data Falls okay I'm talking about now and the error produced by the check relay is related to the presentation layer okay so just want to show you something here's the simple hierarchy of two components and so here I'm going to update the property text of the parent component after angular checked the parent component so I'm using after view checked hook here I'm injecting a parent component I'm updating its property okay so if I run this code and open the console what I'm gonna see the error right so we're just doing what we aren't supposed to do but what's interesting is that what if I now move that code outside of after if you checked and put it in different hook only need am I going to see the error on the console now and it's weird but there won't be error there and it's very surprising to me and I saw a thread on github people wondering how is after view checked hooks so special why we cannot pull put our update code into this hook but can't put it into other hooks and to understand this you need to know what exactly angular does children change detection and the order what is important is the order of operations and we already know where we can find them the function check and update to you the one I showed you earlier right this is the function that runs all operations for a view here's part of the code from that function and this is the line where angular process bindings runs over bindings and performs rendering but you can see here also other operations like calling lifecycle hooks and you can see that some of the hooks are called before the rendering part and some hooks are called after the rendering part okay here's the other diagram so this very important pay attention if you haven't paid attention before look at it now so I'm going to show you what angular exactly does when it checks parent component so first it updates input bindings for the child component okay this is something that you use input decorator right on the child control this is updated during change checking a parent component then it calls only need to check and own changes hooks on the child component keep in mind that we're checking now parent component but calling hooks on the child component and it makes sense right because we just updated all input bindings on the parent on the child component so we want to notify the component that all bindings have been initialized okay make sense now angular runs over bindings basically performs rendering for the current parent component and then it runs change detection for the child component and it calls the after view checked and view need hooks for the child component again makes sense because it just checked the child component previous operation right so just once to let the component know that it's been checked so we can do whatever you need and as you can see the hooks only need on changes and do check are executed before angular process bindings and evaluate expressions for the for the current parent component and after V Jack is called after that that's wife we put the code in different hooks we get different results okay we've learned I think you've learned quite a lot I hope so where do you go from here I've written a lot of articles like 60 on angular internals so you don't need to read all of them but I recommend you read the following articles so this one is about expression changed error so it provides an elaborate explanation of the error of the error basically what I just told you but in a more elaborate way and also outlines common use cases when this error occurs and possible fixes ok then change detection this article outlines list of five articles that you need to read to become an expert in change detection in angular and the last one on the reverse engineering what I've told you today basically what I've been writing about and speaking at other conferences I've learned by reading sources and debugging which is reverse engineering sort of reverse engineering right and to me this is the most rewarding way to learn yet I admit it's very very challenging so this article summarizes my experience doing that over the period of one year and provides some guidelines how you can can start doing that and yes also outlines some interests in debugging techniques so please check it now if you have any questions this is the t-shirt I'll be wearing walking on the hallway so stop by say hi ask questions follow me on twitter for more insights because I regularly tweet about the stuff I find inside the framework interesting use cases I promise I won't waste time it's very very important I have plans to write a follow-up article on on this talk so expect some tweets quite soon and a mountain so my talk has come tuned and I hope that the knowledge that you've learned today that we've covered today has awaken your curiosity and the thirst to know more so I encourage you to never stop learning you'll be able to reach new heights every day because I want you all guys to be extraordinary engineers thank you for your attention and good luck [Applause] [Music]
Info
Channel: AngularConnect
Views: 21,843
Rating: undefined out of 5
Keywords: angularconnect, angular, angularconnect 2018, angularJS, angular conference, javascript
Id: DsBy9O0c6eo
Channel Id: undefined
Length: 29min 36sec (1776 seconds)
Published: Fri Nov 16 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.