Home > Web Front-end > JS Tutorial > body text

Detailed graphic explanation of changes and change detection in JavaScript frameworks

黄舟
Release: 2017-03-09 14:50:56
Original
1217 people have browsed it

Detailed graphic explanation of changes and change detection in JavaScript frameworks

After entering 2015, developers have more choices regarding JS frameworks. In addition to Angular, Ember, React, and Backbone, a large number of competitors have emerged. There are now too many frameworks to choose from.

Everyone can compare these frameworks from different perspectives, but I think one of the most interesting differences is the way they manage state. In particular, it is very meaningful to think about how these frameworks do what they do when the state changes frequently. In these frameworks, what methods do they use to respond to changes in the user interface?

Managing application status and consistency of the user interface has been a source of complexity in UI development for a long time. So far, we have a few different ways to deal with it. This article will take a look at a few of them: Ember's data binding, Angular's dirty checking, React's virtual DOM and its interaction with immutable data structures. relation.

Displaying data

The basic task we are going to talk about is about the internal state of the program and how to put it into visible elements that are displayed on the screen. You take a set of objects, arrays, strings, and numbers, and turn them into a tree structure of text, forms, links, buttons, and images. In web development, the former are often expressed as JavaScript data structures, and the latter are expressed as DOM.

We often call this process "rendering". You can think of it as "mapping" your data model into visible user interface content. When you render data using a template, you get a DOM (or HTML) to represent the data.

The process itself sounds simple enough: although mapping the form data model to the UI may be non-trivial, it is a very straightforward conversion process from input to output.

# Things get challenging when we mention that data changes frequently. When the user interacts with the UI, or something changes in the world that updates the data, the UI needs to reflect those changes anyway. Moreover, because the operation of rebuilding the DOM tree is an expensive operation and consumes a lot of money, we are willing to do as little work as possible to update the data to the screen.

Compared to just rendering the UI once, there is a more difficult problem because it involves state updates. This is also where a few different scenarios come up.

Server-side rendering: start all over again

"There is no change, the universe is immutable"

Before the great JavaScript era, every one of you Interaction with the web page will trigger a back-and-forth interaction on the server side. Each click and each form submission means that the web page is reloaded. A request is sent to the server side. The server processes and responds to a brand new page. The browser then reloads the page. Render it.

In this case, the front end does not need to manage any state. Every time something happens, everything is over and the browser does not care about anything. No matter what the status is, it is managed by the server. The front end is some HTML and CSS generated by the server, and maybe a little bit of javascript.

From a front-end perspective, this is a very simple method, and the processing is also very slow. Not only does each interaction mean a re-rendering of the UI, it is also a remote interaction process in which data is returned to the remote data center and then returned to the front-end interface from the remote.

Now, most of us don’t do that anymore. We can initialize the state of our application on the server side and then manage this state on the front end (a large part of this isomorphic JavaScript article talks about this), although there are still some people who use this more complex method successfully. Way.

First generation JS: Manual redraw interface

"I don't know where to redraw, please point it out"

First generation JavaScript frameworks, like Backbone.js, Ext JS, and Dojo, introduced real data models to the browser for the first time, replacing lightweight scripts that only decorated the DOM. This also means that for the first time you can change state on the browser. The contents of the data model change, and you reflect these changes to the user interface.

Although these frameworks architecturally separate the UI code from the model, synchronizing the two still has to be done by yourself. When a change occurs, you get a set of events, but it's up to you to indicate which part needs to be re-rendered, and how.

The performance of this model leaves application developers a lot of room for development. Since you control when what content should be updated, you can fine-tune it if you want. There is often a trade-off between simply re-rendering large areas of the page versus updating only the small portion of the page that needs to be updated.

Ember.js Data Binding

“Because I control the model and the view, I know exactly what should be redrawn.”

Being able to manually point out what state has changed and needs to be re-rendered is the main source of complexity in the first generation of JavaScript applications. A large number of frameworks are designed to eliminate this part of the problem. Embe.js is one of them.

Ember is similar to Backbone. When changes occur, events are emitted from the model. The difference is that Ember also provides some functionality for the receiving end of the event. You can bind the UI to the data model, which means that a listener is attached to the UI to listen for change events. This listener knows what should be updated after receiving the event.

This creates a very effective change mechanism: by setting up all bindings at the beginning, the cost of synchronization becomes less in the future. When something changes, only those parts of the application that really need to change change.

In this approach, the biggest trade-off is that when the data model changes, Ember must be notified of these changes. This means that your data must inherit Ember's specific API, and you need to modify your data to add a special set method. You can't use foo.x=42 you have to use foo.set('x',42), etc.

In the future, this method may benefit from the arrival of ECMAScript6. It can use the binding method to let Ember decorate a general object, so that all code that interacts with this object no longer needs to use this set conversion.

AngularJS: Dirty Check

“I don’t know what changed, I just checked everything that needs to be updated”

Similar to Ember, Angular The goal is also to solve the problem of having to manually re-render after changes are made. However, it uses another method.

When you refer to your Angular template code, such as this expression {{foo.x}}, Angular not only listens for this data, but also creates an observer for this value. After that, whenever anything changes in the application, Angular checks to see if the value in the observer has changed since last time. If it changes, re-render the value to the UI. This way of handling inspection observers is called dirty checking.

The biggest advantage of this detection method is that you can use whatever you want in the model, and Angular has no restrictions on this - it doesn't care about it. There is no need to inherit the base object or implement a specific API.

The disadvantage is that since the data model does not have a built-in detector to tell the framework what has changed, the framework has no way of knowing whether there has been a change, or where exactly it has changed. This means that model changes need to be checked externally, which is what Angular does: no matter what changes, all observers are run: click event processing, HTTP response processing, timeout, etc., will generate a Summary, this is the process responsible for running the observer.

Running all observers every time sounds like a performance nightmare, but it's actually lightning fast. This is usually because no DOM access occurs until a change is actually detected, and the cost of checking references in pure JavaScript is still quite low. But when you encounter a large UI or need to re-render frequently, additional optimization measures are essential.

Like Ember, Angular will also benefit from the upcoming standards: EMACScript7 has the Object.observe method that is suitable for Angular, which gives you a native API to observe the properties of objects for changes. Although this doesn't satisfy all of Angular's needs, since observers don't just observe simple object properties.

The upcoming Angular2 will also bring some interesting updates about front-end update checks. There was a recent article about this article published by Victor Savkin. You can also take a look at what Victor said in ng-conf

React: Virtual DOM

"I don't know what changed, so I'm going to render everything and see what's different"

There's a lot of fun with React Features, the most interesting of which is virtual DOM.

React is similar to Angular in that it does not force you to use a model API. You can use any objects and data structures you see fit. So, how does it keep the UI updated after changes?

What React does is allow us to return to the days of old server-side rendering, where we can simply ignore any state changes: every time something changes somewhere, it redraws the entire UI. This can greatly simplify UI code. You don't care about maintaining state in React components. Just like server-side rendering, you render once. When a component needs to change, it is re-rendered again. There is no difference between the first render and subsequent renders with updated data.

This sounds extremely inefficient. If React only did that, that would be it. However, React uses a special way to re-render.

When React UI renders, it first renders to a virtual DOM. It is not an actual DOM object, but a lightweight pure JavaScript object structure, which contains simple objects and arrays to express reality. DOM object. There will be a special process to obtain this virtual DOM to create real DOM elements that can be displayed on the screen.

Then, when there is a change, a new virtual DOM is generated from the change. This new virtual DOM reflects the new state of the data model. React now has 2 virtual DOMs: new and old. It uses a difference comparison algorithm on the two virtual DOMs to obtain the set of changes. These changes, and only these changes, will be applied to the real DOM: new elements are added, attribute values ​​of elements are changed, etc.

A very big benefit of using React, or at least one of the benefits, is that you don’t need to track changes. No matter when or where something changes in the new results, you just need to re-render the entire UI. Virtual DOM's difference checking method automatically does this for you, thus reducing a lot of expensive DOM operations.

Om: Immutable data structure

“I can clearly know that those things have not changed”

Although React’s virtual DOM technology has been very It's faster, but when the page you want to render is large or very frequent (more than 60 times per second), there will still be a performance bottleneck.

There is really no way to avoid re-rendering the entire (virtual and real) DOM, unless you make some special controls when changing the data model, like Ember does.

One way to control changes is an immutable persistent data structure.

They seem to work well with React's virtual DOM methods, as demonstrated by David Nolen's work with the Om library based on React and ClojureScript.

The saying about immutable data structures is this. As the name suggests, you cannot change an object, you can only produce a new version of it: when you want to change the properties of an object, if you cannot change It, then you can only create a new object and set it to this new property. Because of the way persistent data works, this works better in practice than it sounds.

When React component states are composed of immutable data, change checking will become like this: when you re-render a component, if the state of the component still points to the last time you rendered it With the same data structure, you can skip this rendering and continue to use the last virtual DOM of this component, as well as the entire internal component with this unchanged component as the branch node. There is no need to continue further testing at this time, because there are no status changes.

Like Ember, libraries like Om don't allow you to use any old javascript object graph in your data. You can only build your model from the ground up using immutable data structures. I would argue that the difference is that this time you don't have to do it to satisfy the requirements of the framework. You do this simply because it's a better way to manage application state. The benefit of using immutable data structures is not to improve rendering performance, but to simplify your application architecture.

Om and ClojureScript are also useful in combining React and immutable data structures, but they are not essential. It might be enough to just use pure React and a library like Facebook's Immutable-js. Lee Byron, the author of this library, gave a great introduction to this topic at React.js Conf.

I recommend you to take a look at Rich Hickey's persistent data structure and reference management. This is also an introduction to state management methods.

I have been using immutable data structures in waxing poetry for some time. Although I can't take it for granted that it will be used in front-end UI architecture. But it seems that this is happening, and the Angular team is also working on adding support for these contents.

Summary

Change detection is a central issue in UI development, and various JavaScript frameworks use their own methods to provide different solutions.

EmberJS can detect changes when they occur because it controls the data model API. When you call the API to make data changes, the corresponding event will be triggered.

Angular.js detects changes after they occur. What it does is to re-run the data binding you registered on the UI, and then see if any values ​​have changed.

Pure React detects data changes by re-rendering the entire UI to a new virtual DOM and then comparing it to the old virtual DOM. Find out what has changed and send it to the real DOM as a revision.

React and immutable data structures can be used as an enhanced version of pure React solutions, which can quickly mark the component tree as unchanged state, because state changes are not allowed inside React components. Disallowing changes to internal state is not done for performance reasons, but rather because doing so has a positive impact on your application architecture.

Translator Information

Translator: Li Bingchen, working in HP software development department, more than 10 years of experience in JAVA product development, familiar with C#, Python, Nodejs. He has extensive experience in Internet e-commerce platforms and enterprise software development and management. My current interests lie in front-end development and the application of data statistical analysis in financial services.


The above is the detailed content of Detailed graphic explanation of changes and change detection in JavaScript frameworks. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!