A while back I shared a couple of posts on Data structures and Algorithms in the Front-end domain.
Article links:
- Application of data structures and algorithms in the front-end domain (Starter)
- Application of data structures and algorithms in the front-end domain (advanced)
This is the third article in a series that will give you a new look at current front-end applications. Although the principles involved are simple, they are rarely seen, let alone promoted and applied.
The new perspective here is that we think about the running of our front-end applications in terms of processes and threads, so that we can view and optimize our applications, and even the whole front-end ecosystem, from a higher level.
I hope you can gain something from thinking and working application.
About me
I am a programmer full of interest in technology, good at front-end engineering, front-end performance optimization, front-end standardization and so on.
Worked on.NET, worked on Java, and is now a front-end engineer.
In addition to my own work, I will do some output and sharing in the open source community, and GitHub has received 1.5W star in total. Popular projects include Leetcode problem solving, the Universe’s Strongest Front-end Interview Guide and my first short book
The browser’s process model
Let’s start by looking at the browser process model, using Chrome as an example.
Chrome has a multi-process architecture, with a Browser process at the top to coordinate the Browser’s other processes.
zhuanlan.zhihu.com/p/47407398
This is why Chrome has four processes open when it only has one TAB open.
This is not the main topic of this section, so that’s enough for you to know, and then we’ll look at the main topic of today – rendering processes.
The browser’s rendering process
The renderer process is responsible for almost everything in the Tab. The core purpose of the renderer process is to convert HTML CSS JS into a web page that users can interact with.
The render process consists of four threads: Main thread, Worker thread, Raster thread and Compositor thread.
Today we are going to focus on the Main thread and the Worker thread.
Main thread
The main thread is responsible for:
- Build the DOM
- Communicate with the network process (mentioned above) to obtain resources
- Parse the resources
- JS code execution
- Style and layout calculations
You can see that the main thread is very busy and needs to do a lot of things. The main thread can easily become a performance bottleneck for an application.
Of course, in addition to the main thread, other processes and threads can also become performance bottlenecks, such as network processes. There are many ways to solve network process bottlenecks, such as using the browser cache, ServiceWorker, and resource optimization. That’s not the focus of this article, but it’s just to give you a new perspective.
Worker thread Worker thread
The worker thread can share the computational burden of the main thread, which in turn can have more idle time and respond more quickly to user behavior.
There are two main types of Worker threads: Web Woker and Service Worker.
Web Worker
The following is taken from MDN
Web workers provide an easy way for Web content to run scripts in background threads. Threads can perform tasks without interfering with the user interface. In addition, they can perform I/O using XMLHttpRequest (although the responseXML and Channel properties are always empty). Once created, a worker can send a message to the JavaScript code that created it,
Service Worker
The following is taken from MDN
Service Workers essentially act as a proxy server between the Web application and the browser, and can also act as a proxy between the browser and the network when the network is available. They are designed, among other things, to enable the creation of an effective offline experience, intercept network requests and take appropriate action based on whether the network is available and whether updated resources reside on the server. They also allow access to push notifications and background synchronization apis.
Rethink our front-end applications
Worker threads, especially Web workers, appear in part to share the burden of the main thread.
The whole process is like the main thread issuing a command, and then the worker thread executing it, passing the result of execution to the main thread in the form of a message.
From the perspective that the contractor contracts the project and then assigns the work to each unit, it looks something like this:
In fact, work processes, and webworkers in particular, have been around for a long time. But a lot of times we don’t use it enough, or even use it.
Taking Web workers as an example, let’s dig into the potential of Worker threads.
In previous articles, we talked a lot about front-end algorithms, both at the framework level and at the application level.
As mentioned above, the React harmonic algorithm takes a lot of time. React16 reconstructs the entire harmonic algorithm, but the overall computation cost is still not reduced or even increased.
For the harmonic algorithm, please refer to another article of mine: Data structure and algorithm interpretation in the front-end domain – Fiber
Is it possible to pull this out of the main thread and give it to the worker process, as shown in the figure above? I think so, and everything I mentioned in the previous series of articles can be executed in a worker thread. Such as state machines, time machines, auto-completion, difference matching algorithms and so on.
If we took these out of our main thread, our application would look something like this:
This way, the main thread is only responsible for the UI presentation, event distribution, etc., which greatly relieves the main thread and allows us to respond to users more quickly. Then, when the calculation is complete, all we need to do is notify the main thread, and the main thread responds. It can be seen that when the project is complicated to a certain extent, the effect brought by this optimization is very large.
Imagine what would happen if popular front-end frameworks like React built in this thread separation feature and handed over the conciliation algorithm to webworkers.
What if we could involve an algorithm that intelligently, based on the hardware and network conditions of the current system, automatically decides which part of the worker thread should be handed over and which part of the code should be handed over to the main thread?
This is actually the legendary heuristic algorithm, you can study it
challenge
The scenario described above is beautiful, but equally challenging.
The first challenge is cumbersome operation, such as Webworker only supports single file import, function serialization is not supported, repeated serialization brings performance problems, and communication with Webworker is asynchronous, etc.
However, there are mature solutions to these problems. For example, we can use some libraries that encapsulate Web worker operations to solve the problem of cumbersome operations. Comlink is a great wrapper for Web workers.
We can use Blob and createObjectURL to simulate single file import. There is a worker-loader that can be used directly if you build with WebPack.
For serialization of functions, there is no way to pass functions to the worker thread. In fact, Comlink solves this problem by using Comlink’s proxy, you can pass a proxy to the worker thread.
For the performance issues of reserialization, we can actually use a technique called Transferable Objects, which fortunately also works well with browsers.
There are certain trade-offs we can take with regard to asynchrony. That is, we locally save a copy of the latest result each time, we just need to return this copy each time, and then update the copy when the webworker calculates the result.
conclusion
The main purpose of this article is to let you think about the current front-end application from a new perspective, we stand in the process and thread perspective of the current front-end application, perhaps there will be more different understanding and thinking.
This article first looked at the browser process model and then looked at the thread model in the browser’s renderer process. We know that the rendering process is mainly composed of four threads, namely Main thread, Worker thread, Raster thread and Compositor thread.
It then introduces the main thread and worker thread in detail, and uses webworkers as an example to show how to use worker threads to share the load for our main thread. To digest this part of the knowledge, I suggest you do it yourself.
Although our wishes are good, there are still some pitfalls in the application process. Here I list some common pitfalls and offer solutions.
I believe that the potential of worker threads has not been fully exploited, and I hope to see the time when front-end applications really tap into the potential of various processes and threads. This requires not only the efforts of front-end engineers, but also the cooperation and support of browsers, and even standardization organizations to push something.
Pay attention to my
Recently I reorganized my official account, and I renamed it “Imagination Front”. It is a key that helps you open the door to a new big front world 🔑, where you can hear novel ideas, see some new technologies, and receive systematic summaries and thoughts.
I will try my best to illustrate some concepts and logic in the form of diagrams to help you understand them quickly. The graphical front end is my goal.
After that, my article will be synchronized to the wechat public account Imagination front, you can pay attention to get the latest article, or communicate with me.