preface
May be a bit clickbait, hahaha. But before you close the page, check it out first.
Hello everyone, I am Ding Ding, a front primary school student. Before I left, my former supervisor told me that I must constantly reflect on the architecture and ask myself Why. This article is to record some thoughts when doing project architecture design recently.
This article does not involve the React source code analysis, just simple from the React architecture design simple talk about some personal thinking.
What is divide-and-conquer
Divide and conquer means “divide and conquer”. This is a design idea that is very common in algorithm design. The specific meaning is to divide the original problem into N smaller sub-problems with similar structure to the original problem.
I understand divide and conquer
I think divide and conquer can be understood simply as divide, as long as you do divide, divide and conquer. Everything in this article is split. It may be a little different from the divide and conquer you are exposed to in your daily life
What does divide and conquer do
Before I answer this question, LET me start with a few examples of divide and conquer in our lives, and then summarize the answer.
The embodiment of partition and rule in life
One, two-way lane
Is it ok if the lanes are not in either direction? The answer is definitely yes. That’s what country lanes are like. There’s no difference between forward and reverse. So why are the lanes in the city segregated? Because it is easy to manage, can improve the traffic through.
So divide-and-conquer here simplifies traffic management by breaking it up.
[Photo from Internet]
Second, census
The national census breaks down questions into provincial, municipal, district, township, street and community levels. By each community to carry out field visits, statistics. And then they report it level by level, and they put all the data from the whole country together and they complete the census.
So divide-and-conquer, in this case, solves a big problem by breaking it down into smaller problems that can be relatively simple.
[Photo from Internet]
A summary of divide-and-conquer
To sum up the above two examples, divide and conquer is to solve a complex problem by splitting it into small problems that can be easily solved, and finally solve a complex problem together.
So, what divide-and-conquer does is help us solve complex problems.
React architecture design: Divide and conquer
I’m talking about [email protected]+. I don’t know much about React architecture either. If I’m wrong, please comment lightly.
React architecture design is full of divide-and-conquer ideas. Here, I will analyze from the top-level design to the low-level architecture design.
React top-level design
Architecture division
React can be roughly divided into three parts:
- Scheduler – Schedules and calculates the priority of tasks
- Reconciler — the components that identify change
- Renderer — Is responsible for rendering changing components onto the interface
There are many ways to render to a page, such as React-DOM on the Web side and React-Native on the APP side. Other options include react-canvas, react-svg, etc.
[Picture originated fromzhihu】
conclusion
In terms of top-level design, React divides a complex task into three parts to realize it, which is actually a manifestation of partition and rule. Each of the three parts is responsible for a complex piece of work, and then organically combined to complete a complex task.
From the architecture design of Fiber Reconciler
Fiber itself can have three meanings:
- As a static JS data structure, it is a simple JS object instance, with many methods and properties above.
- As a dynamic unit of work, fiber is used to add, delete, modify, and check nodes, change nodes, and calculate nodes in React instances.
- As a kind of architecture, during the instance running, diff of the changing part is completed through the design of double cache tree, and then the changing part is updated to the interface.
What is the Architecture of The Fiber Reconciler
Fiber Reconciler is a new feature architecture introduced by Act 16 to address CPU bottlenecks. Specifically, React components and DOM nodes are stored through Fiber nodes. In the recursive update process, data is accessed through Fiber nodes.
The way in which Fiber Reconciler is scheduled[Picture originated fromnetwork】
The way in which Stack Reconciler is scheduled[Picture originated fromnetwork】
Why is there a Fiber Reconciler framework
Is it ok without Fiber architecture? It can, and act15 and its lower versions use the Stack Reconciler architecture to build large applications.
So why Fiber architecture? React performance was limited by CPU bottlenecks, and Fiber was introduced to address performance issues. Here’s a quick explanation of the performance limitations and how to resolve them.
When there are too many nodes to update, the Stack Reconciler, which is limited to JS’s single thread, consumes the CPU for a long time for calculation, and the page freezes when the calculation takes longer than one frame in the browser (in chrome’s case, a frame is 16ms, based on a refresh rate of 60HZ). There are two ways to solve the problem:
- Bypassing the single-thread limit and using workers to do calculations, the main thread is only used for rendering and handling interactions.
- Synchronous mutation step, the synchronous calculation into asynchronous interruptible calculation, using the browser event loop mechanism, automatic scheduling calculation and rendering.
React uses the second approach, asynchronous interruptible computation. In doing so, Fiber architecture was introduced.
As for why Worker is not adopted, I guess there are two reasons. On the one hand, Worker is too limited, and almost all DOM related, Cookie related and window-related items cannot be accessed. On the other hand, passing data between threads is also a time-consuming operation, and there is no way to pass reference types between threads (Shared Memory is another word), so events and Fiber instances cannot be passed and diff and other things cannot be done properly.
conclusion
In the context of the Fiber Reconciler’s architecture, asynchronous interruptable updating is a solution to the CPU bottleneck by breaking down an intractable problem into asynchronous computing, which can also be seen as the idea of divide-and-conquer.
From the double cache tree design
What is a double cache tree
The React instance maintains two Fiber trees (the Current Fiber tree and the WorkInProgress Fiber tree) when it runs. The Current Fiber tree corresponds to the DOM tree displayed on the interface at this moment, while the WorkInProgress Fiber tree is the Fiber tree used to calculate changes in memory when updates are made. Both trees are made up of Fiber nodes, all of which are data stored in memory.
[Picture originated fromnetwork】
Why a double cache tree
Can we do without it? I haven’t done much research on this, but MY guess is that there might be a way to solve the problem with just one tree, but the complexity would skyrocket.
So one of the reasons for introducing a dual cache tree design should be to reduce complexity. We have to mention the famous Diff algorithm. This algorithm is actually used to decide whether to reuse the Fiber node in the Current Fiber tree or update the Fiber node.
conclusion
Double cache trees can certainly reduce complexity by splitting the state and saving it in both trees, then diff out the changing nodes and update them to the interface with each update. This is also the idea of divide and conquer.
In terms of life cycle design
React component lifecycle design
The React lifecycle refers to the three phases in which components run: Mount, Update, and Unmount. Each stage can be subdivided into smaller stages.
[Picture originated fromnetwork】
Benefits of lifecycle design
Supporting the lifecycle from the architectural level and providing multiple lifecycle hook functions at different stages can give components richer performance and customization capabilities.
If the architecture doesn’t support lifecycle hooks and we have to maintain them ourselves, the complexity of component maintenance can quickly increase.
conclusion
Life cycle design is actually a component running state divided into multiple phases to reduce the complexity of the component design itself. There’s also the idea of divide-and-conquer.
From the component separation point of view
Can components be unsplit
You can. I don’t know if you’ve ever seen a component where the entire complex page or even the entire application has only one component, and that component has only one method, and then all the code is written in Render, and all the logic is implemented in Render.
class XXX extends React.Component {
render () {
return (
// Omit 2000 lines of code here)}}Copy the code
Is there a problem with this code?
Maybe there’s a problem, or at least my perception would say there’s a problem.
Maybe there’s no problem. After all, this code works.
What is component splitting doing
Component separation is divided and encapsulated into separate modules based on different functions, logical units, and responsibilities. It could also be that the team’s code specifications require different fine-grained components to be split and encapsulated. The former can greatly reduce the difficulty of debugging, the latter may be more beautiful.
conclusion
Splitting and encapsulating complex page structures and logic into different components also involves the idea of divide-and-conquer, which can simplify complex problems.
conclusion
The purpose of partition
The purpose of divide and conquer is to simplify complex problems, to break down intractable problems into manageable ones.
Divide and conquer is everywhere
In life, a lot of design ideas are full of divide and conquer.
At work, as migrant workers in the new era, the code we face every day is also filled with the idea of divide and conquer. For example, if else in your code might be part of your divide-and-conquer thinking.
Give me some inspiration
What is architecture doing
My own narrow interpretation is that architecture is by nature a demand-oriented solution, so different projects will have different architectures. Architecting is responsible for the long-term maintenance of the project.
What architects do is to be able to think clearly and thoroughly about a large complex system, and at the same time to break up the large system into loosely coupled modules, and finally to assemble and integrate these modules through predefined interfaces after the development of each module independently and in parallel.
Anyone can be an architect
Architecture is requirements oriented, and architects who do not understand requirements cannot design a reasonable and appropriate architecture. Engineers can also be architects of requirements when implementing requirements. The same requirements can be implemented in different ways. How to gracefully implement a set of maintainable code can also test one’s architectural ability.
Special thanks to
Cazon. – Cazon the Magician