Please indicate the source of reprintPrinciples and prospects of cross-platform UI frameworks
This article is published simultaneously on the wechat public account "Yuanchuangunion". You can scan the QR code at the end of the article to follow and get the latest article.Copy the code
Before you start, agree on some technical terms
- Cross-platform technology: Cross-platform development kits are available to run the compiled technology on a variety of devices (Android, iOS, PC, etc.), usually to develop console applications and GUI applications
- Cross-platform UI framework: The cross-platform technology used to develop GUI applications, which is just a subdivision of cross-platform technology, hereinafter referred to as “UI framework”
- Cross-platform UI rendering engine: a module in the UI framework responsible for rendering, hereinafter referred to as “rendering engine”
Before we talk about principles, let’s first understand the evolution history of UI frameworks, and first understand the problems and limitations of current UI frameworks so that we can make design more appropriate for this stage.
1. UI framework evolution
A UI framework usually consists of several parts
- Kernel: source code management (packaging, loading) + rendering engine (layout, drawing, composition, events, animation)
- Ecology: expand opening to the outside world, enrich components, and improve the developer ecology
- Development supporting facilities: from development, integration, testing, release of the whole R & D process supporting facilities construction
The “kernel” is the core part of the UI framework that provides extensibility, third-party participation, and various components to complete the development ecosystem. Typically, development kits are customised by the companies using the technology.
In the process of the transition from PC Internet to mobile Internet, cross-platform UI development has become a hot field, and many UI frameworks have emerged successively, represented by PhoneGap and AppCan of WebView technology in the early stage, and React Native and Weex in the middle stage. Recently represented by Flutter. Why are UI frameworks such a hot technology for big frontend? A set of code, multi-terminal reuse, can save the development cost of multiple terminals, said to the company can really save a small labor cost. According to my practical experience, dual-end multiplexing can roughly save about 40% of the cost. The statistical method is mainly based on two points: HC and the number of completed requirements for each iteration. Of course, as you become more proficient in cross-platform technology, this number will be higher, and still considerable. Other aspects depend on the needs of the market, each stage has different appeals, and the UI framework solves different problems. The general overview is as follows
1.1 Stage 1: Represented by WebView technology
Focus on solving problems
- Development cost: build App quickly and reuse on multiple platforms
App became popular in the early stage, and there were not enough Android and iOS developers in the market. How to build an App in the most efficient and fastest way was the main problem to be solved in the early stage of cross-platform UI framework, so PhoneGap and AppCan emerged.
1.2 Stage 2: React Native is represented
Focus on solving problems
- Development cost: WHAT you see is what you get, reuse across multiple platforms
- Performance experience
- Dynamic: Rapid iteration, hot repair
- Packet size
With the development of mobile Internet, various companies began to bet on mobile Internet, App development technology mature, the number of developers increased significantly. Startups are so crowded that each track is packed with hundreds of them. In such a fierce competition, the quality of App gradually becomes important, and experience gradually becomes the focus of attention. Various App quality monitoring platforms gradually emerge, and experience-related data indicators gradually begin to be standardized (such as FP, FCP, FMP, etc.). App experience developed based on WebView technology is obviously inferior to Native, so cross-platform UI frameworks are constantly approaching or catching up with Native performance. React Native and Flutter are all in pursuit of more extreme performance experience.
At the same time, it also generates dynamic demands, because Chinese companies are too anxious and always worry about their products’ problems leading to the loss of users. Therefore, rapid iteration, rapid trial and error and hot repair have become important universal appeals for Chinese companies, while foreign companies do not have such appeals, at least not strong appeals.
With the gradual disappearance of demographic dividend, the cost of acquiring customers is getting higher and higher, and the requirement for new conversion rate is also higher. Package size has a great impact on the promotion and promotion of independent apps. For some platform apps, if the package size is hundreds of meters, the conversion rate of new apps will be low. At this time, the control of package size is particularly important. Package size is also a strong concern at this stage.
Why Web based technology? In the process of the transition from PC Internet to mobile Internet, the products of major companies have also completed the migration from browser to App, and the Web technology stack has been naturally transplanted to the App technology stack. First, most of the senior technical managers of the early companies are experienced Web developers (from the current situation, the big front-end leaders are also from the Web), and technical personnel have their own technical preferences, so it is a matter of course to apply the Web technology stack to App development. Secondly, the Web technology stack has obvious advantages over the App native technology stack
- What you see is what you get: No need to wait for compilation, greatly improving development efficiency
- Modification means update: you can dynamically update product functions without upgrading App
React Native is in this context, applying the Web technology React to the App development stack (Weex is also a fad). It has great advantages in dynamic and packet size control, and its performance is mediocre.
I have used React Native for more than a year and participated in a lot of business development. The performance is far from the official publicity, and it is nowhere near as good as Native. For more on how React Native works, see my article on how to Understand React Native technology in depth. The underlying reason for the poor performance is JavaScript, which is a weak language, but there is no cheaper solution for dynamics and package size control (not that there are other alternatives, but the cost is high, more on that below). Even after Flutter appears, Companies still want to add another layer of JavaScript to Flutter, calling it Web on Flutter.
1.3 Stage 3: Flutter is represented by Flutter
Focus on solving problems
- Development efficiency: What you see is what you get, reuse across multiple platforms
- Performance experience :(AOT mode) the same performance as Native
- Multi – end consistency: self – rendering technology, multi – end consistency
React Native doesn’t solve the problem of performance experience. Compared with WebView, it uses Native controls to render, so it can’t display consistently in many aspects. Instead, it is a pitfall. The emergence of Flutter solves the problem of multi-terminal consistency (in fact, it has been in development for a long time. It was originally called Sky Engine, but Sky still exists in the source code). It features self-rendering technology and resolves the problem of two-terminal inconsistency.
Flutter can rival Native in terms of performance. It has the same streamlined rendering process as Native and also supports GPU acceleration. For details, see my article on Flutter High-performance Rendering Principles.
Unfortunately, it does not support dynamic behavior, which is an important reason for Web on Flutter. No matter what framework it is, the package size of the App will increase for no reason. The package size of the framework itself is very large, not to mention the business code. Flutter performs poorly. React Native does a better job of reducing the size of the installation package by dynamically delivering JavaScript. The Solution of Web on Flutter can solve the problem of dynamic behavior. At the same time, compared with React Native, the two-terminal consistency is better, but the performance experience is lost.
How should future UI frameworks be designed to meet both performance and dynamic needs? Before talking about this topic, it is important to understand the technical principles of UI frameworks.
2. UI framework principle
UI framework is mainly divided into source code management and rendering engine two parts.
2.1 Source Code Management
Source code management can be roughly divided into “packaging” and “running” two stages, packaging is more through the offline CLI packaging tool chain to complete, running is the actual execution of the generated file packaging, these two stages respectively focus on the point is not the same.
Packaging phase
- Development: Focus on “development efficiency”
- Editor: What you See and what you get, live preview
- Hot Reload: Real debugger preview, changes will take effect immediately, greatly reducing the waiting time for full compilation
- Release period: The main issues are code protection, package size, performance
- code
- Code confusion, extra mapping file generation (code protection, package size)
- Tree-shaking, removing useless resources and code (package size)
- Compilation optimizations to improve run performance, such as AOT compilation (performance)
- Resources: Digitized resource IDS (for binary lookup)
- code
Operation phase
- Load: Perform preparation environment
- Code and resources: Code is loaded into memory synchronously and resources are read asynchronously
- Environment preparation: Initialize necessary objects (such as virtual machines, View instances, etc.)
- Execution phase: The execution entry begins the rendering process
If you design a new UI framework, make sure that all aspects of source control are well implemented and will be user-friendly. Dynamic support depends on how source code is packaged at release time and how the corresponding UI framework loads parsed source code. In the design of the new UI framework, different designs and support for “dynamic” and “performance” can be made at this stage.
2.2 Rendering Engine
The main work of the rendering engine is divided into three parts
- Render: build Tree, layout, draw, compose
- Interaction: Events
- animation
2.2.1 Design of thread model
In general, rendering engines can be designed with two threads: the UI thread and the GPU thread
- UI threads: build Tree, layout, draw, event
- GPU thread: composition
The UI thread does a lot of work and is a heavy thread. The advantage of putting events on the UI thread is that the display and interaction are one and the same, and there is no need for the UI to have a lot of unfinished operations when an event occurs. The typical example is a WebView, and the event handling of a WebView is a single thread, so a long list, you can scroll through it indefinitely, and if the UI thread can’t keep up, you’re going to have a white screen, which is essentially a thread design problem.
2.2.2 build Tree
Each element on the interface is called a Node, and each Node is managed by a Tree structure. Tree generation can be done in different ways, but the most atomic operations are CRUD (add, delete, search, modify). There is nothing to say about this part, just the API that implements CRUD.
2.2.3 typesetting
The Layout process mainly consists of “Measure” and “Layout”. Measure mainly calculates the Size of elements to get Size. Layout mainly positions elements to get relative Position Offset or absolute Position. Position + Size determines how much of an element is displayed on the screen.
The most complicated part of this process is the selection of the typesetting algorithm. Different methods for node calculation vary greatly (for example, CSS box models have static, absolute, relative typesetting methods). However, no matter how they are arranged, there are only two types of “father decides child” or “child decides father”. The following DOM structure is illustrated
Note: Blue is the leaf node, red is the parent node, max-w/max-h is the maximum value, w/h is the expected value, assuming the window size is 800 x 600
- Parent determines child (fixed value) : node 1 [800, 600], node 2 [100, 50], node 3 [50, 50], node 4 [50, 50], node 5 [5, 5], node 6 [50, 50]
- Child determines parent (auto adaptive) : The parent controls need to wait for all the child controls to determine the size, and then go back to determine its own size. Node 5 [w = 800 x 20% x 10%, h = 600 x 20% x 10] = [16, 12], node 3 is jointly determined by node 4 and node 5, and the size is [66, 62].
In the above algorithm, only the width and height are calculated. In actual calculation, it is correct to add the margin, border and padding values in the box model, and these values are also affected by max-w and max-h.
This is similar to WRAP_CONTENT on Android, but may not be implemented in the same way. If the size of the child node changes, the parent node will also change. In the worst case, the size of the entire tree will change. So how to rearrange when the node size is changed?
- The first method: rearranges all nodes from the Root node with the lowest performance
- Second: rearrange from the first ancestor node with fixed size (fix mode)
The first way is more violent, which is the worst, and the second way is a compromise, but if the whole tree is auto, it’s the same as the first way.
Measure: Calculates the final size of each Node. Margin [left, top, right, bottom], border[left, top, right, bottom], padding[left, top, right, bottom], Content [width, height] Specifies the actual size.
Layout: Sets the Offset or Position according to the calculated size
- Offset[x, y] with respect to parent
- Position[x, y] relative to the origin of screen coordinates
Once the typesetting process is complete, the element’s “position + size” has been determined, and the area on the screen has been determined.
The most efficient typesetting algorithm is absolute typesetting, which is all “father decides child” with no backtracking process. Flexbox typesetting algorithm is also “father decides child” typesetting algorithm, performance is also better. Based on React Native’s experience, Flexbox can meet most business scenarios and is a standardized layout algorithm, making it a good choice. Custom Layout algorithm is not recommended, because it will increase a lot of learning costs, Android a bunch of Layout controls, looking very annoying, and many controls Layout performance is poor.
2.2.4 Drawing and synthesis
The process of painting is to turn each Node into a “layer” of its own Size. This layer does not necessarily refer to an in-memory Bitmap, it is just a virtual concept, it can be a collection of drawing operations, not necessarily to the Canvas.
Composite, also known as rasterization, is the process of drawing layers on the same Canvas in sequence according to the z-order of layers and combining them into pixels. Canvas can be provided by GPU type Surface or CPU type Surface. There are two main points to note here
- Hierarchy order: lower levels are drawn first, higher levels are drawn later
- Overflow processing: Whether the child node can overflow display
Hardware acceleration: Canvas is just a virtual Canvas, and the memory space for real drawing is provided by Surface. If the memory space is allocated directly on GPU, the drawing efficiency will be greatly improved. It can be directly operated by GPU 3D graphics library (such as OpenGL, DirectX and Metal). These GPU graphics libraries are designed for 3D games with the best graphics performance, much better than CPU simulation drawing performance.
Same-layer Rendering: Another tricky point here is composition with platform UI controls, which may or may not be drawn directly from the existing Canvas. For example, in the Android system, UI control drawing is completed in the platform UI thread, while the rendering engine usually completes the synthesis operation in the newly created GPU thread. At this time, it either turns to the platform UI thread for synthesis, or draws the platform UI controls into pixels and then synthesizes them in the GPU thread. The technical term of this industry is called “same layer rendering”, which means that the platform UI control and the UI framework control are also drawn in accordance with z-Order rules, mixed composition, this mode will reduce the performance of the synthesis stage, if possible, do not use.
Double buffering mechanism: there is a concept called double buffering, its principle is to draw a copy version in memory, draw good and then one-time copy to the real display memory, and then one-time draw on the screen, each frame display is complete, and batch operation performance will be relatively high.
The complete flow diagram is shown below
Drawing and composition rely on graphics library, a better choice is Skia 2D graphics library, which is cross-platform and fundamentally solves the problem of consistency of drawing. After years of development, Backend not only supports CPU rendering, but also supports multiple GPU graphics libraries. It encapsulates mainstream GPU 3D graphics engines (OpenGL ES, Metal, etc.) to learn how to use Skia apis. Drawing and compositing are less of a problem.
2.2.5 event
Events are mainly divided into two parts: event abstraction and event transfer.
Event abstractions: DOWN (press), UP (lift), MOVE (MOVE), HOVER (HOVER), other events can be obtained with these combinations
- Click events: Essentially a combination of DOWN and UP, with short intervals
- Long Click event: Essentially a combination of DOWN and UP with a long interval
- Scroll event: essentially a combination of DOWN and MOVE
- .
Event passing: The passing process includes capturing and bubbling. Personally, I think the event model of W3C is relatively excellent. In the capture stage, we mainly do hit test to see whether the event occurrence point [x,y] falls into the display area of the control. We need to consider z-order and cannot directly walk through the Tree. Below is a schematic of the W3C event bubbling
2.2.6 animation
The essence of animation is to trigger timed changes in Node properties, which in turn cause rearrangements or redraws. If the changing attributes affect the layout, rearrangement, rearrangement triggers redraw. If the changing attribute only affects the display, only redraw is done. The classification of animation can be simply divided into numerical animation, frame animation, custom animation.
Numerical animation: set the three fixed values of total time T, animation value START and animation value END, take the current time T as the change quantity, and calculate the current animation value value through the function (generally called slow function).
For example, the element takes 1s to move horizontally and uniformly from point A to point B
- Total time T: 1s, T
- START: the x-coordinate x1 of point A
- Animation value END: x coordinate x2 of point B
- T: increment time, starting from 0
- (x = t/ t, a and b are constants, a = x2 – x1, b = x1)
Tween has many calculation formulas and can achieve many interesting animation effects.
Frame animation: it is a special case in numerical animation. Set the total time T and the total number of frames, take the current time T as the change quantity, and obtain the current frame by calculating the constant speed function.
Animation library: whether numerical animation, frame animation or custom animation, all need a powerful animation library support, specifically reflected in
- Response speed: Response speed in milliseconds
- Ease of use: flexible use, such as multiple animation parallel, serial, etc
- Extensibility: process monitoring of animation state, how to customize animation
These are also things to consider when designing animations.
2.3 summarize
Above, is the core principle of the entire UI framework, I wrote in 5 years ago UI framework is according to the above ideas: github.com/myz7656/sma… (UI framework on Windows platform), implementing a simplified version of the UI framework is not complicated. Back to the current issues with mainstream UI frameworks
- React Native: The performance is poor and the two ends are inconsistent
- Flutter: cannot be dynamic or solve App package size problems
How should future UI frameworks be designed to meet these requirements?
3. Future outlook: full scene, building block and self-drawing
Focus on solving problems
- Development costs
- Performance experience
- Multiterminal consistency
- dynamic
- Packet size
Dynamic and performance experience are a contradiction point, and dynamic will surely sacrifice part of performance experience. Not all businesses of an App need dynamic, and a good UI framework should be able to solve the demands of all scenes, such as the strong demands of the App home page
- First effective drawing time: that is, whether the FMP indicator (the time when the increase of visible elements on the first screen tends to be stable) can reach the level of seconds
- First interaction time: TTI metric (how long screen elements respond to valid clicks)
This scenario is obviously not suitable for loading heavyweight UI frameworks, as frameworks like WebView and Flutter take hundreds of ms to draw the first frame from loading to GPU, making optimisation impossible.
However, some active pages, such as pages with small PV, should not occupy too much of the package size of the App, which can sacrifice part of the experience and load dynamically.
Whether it’s WebView, React Native, or Flutter, the above “virtual machine” BASED UI frameworks are overstretched. The result is
- Slow start
- High memory usage
Here is a rough comparison of FMP indicators
- Native: only processes for parsing XML, typesetting, and rendering
- React Native: Because JavaScript is weak, even engine caches don’t perform as well
- Flutter provides almost the same page loading performance as Native with engine cache, see the principle article above
- Web on Flutter is even more of a disaster, with two virtual machines and high memory consumption. All warmed up compared to React Native
- Performance: about the same, who better than who, the key to see the internal design implementation details
- Multi-endpoint consistency: Better (thanks to Skia)
- Number of platforms supported: More (thanks to Skia)
In essence, the Web on Flutter solution makes up for the number and consistency of React Native’s multiple terminals, resulting in extremely complex architectural design, high technical challenges to stability and quality, and more system resources (CPU and memory).
Generally speaking, in existing businesses, the UI framework can only be applied to business development in the form of “add to APP”. Under the condition of the company’s products have been mature, a new framework developed popularization, it’s hard to do 100% business 100% stock code is not likely to migrate to the new framework, as a latecomer, just a secondary option, so these problems become must solve the problem, don’t solve the problem is “looks worse performance. Slow startup can be solved by preheating and engine caching, but this will consume extra resources (CPU and memory). In a platform App, resources are limited. If you seize the thread, other services have to wait, which is not a perfect solution. As Mentioned in Ali’s article, there are about 3 containers in an App. If each container is preheated, it will be a big memory overhead. It depends on whether to trade time for space or space for time. You cannot have your cake and eat it too.
Therefore, to meet the support of the whole scene, it is necessary to refine the UI framework into modular and separable combination, the source management (compilation, loading) and the rendering engine are separated, two-stage design, the rendering engine only focuses on the core (typesetting, rendering), different scenes can be free combination of building blocks
- High performance Scenarios: Rendering engine + (Template)
- Dynamic Scenes: Rendering engine + (Virtual machine + dynamic language)
How do you design it? Web technology is very mature and well worth learning. It is good for everything except performance, and can do all of the above goals. The reason for the poor performance of WebView itself is that it carries with it historical baggage from the W3C
- Startup performance: The container itself is very heavy, and many things need to be initialized, such as JavaScriptCore/V8 virtual machine environment
- Rendering performance: it has a more complex rendering flow and threading model, which is also being improved. However, due to compliance with all W3C standards, rendering requires many unnecessary steps, such as flex-shrink, which may lead to a double shrink process
For a more in-depth look at WebView, see this article: Browser technology evolution from the Blink kernel Rendering Architecture. Many browser makers in China claim to be faster than Chrome. Is it true that Google’s engineers are not as good as those in China? No, there’s only one way to optimize: get rid of the old baggage and get rid of the standards that drag down performance. That’s the only way to do it. (I like apple’s approach. The W3C standard is long and stinky, and is not really used much in everyday development. Flutter probably just got tired and started all over again.
Rather than reinvent the wheel, I prefer to tailor an old standard to implement the more common “subset” of W3C standards. The reason is naturally “car with track, book with text, line with the same”, since it is called the big front end, it should be unified standards, rather than the development of new standards
- Unified cognition: reduce the cost of learning and communication
- Easy migration and adaptation: interworking with large front-end wheels, no matter how many wheels there are at the front end, there are only two forms to the browser
- CSR: Client-side rendering mode that generates pages on the client side by executing JavaScript and calling the DOM API
- SSR: server rendering mode, through the server generated HTML, CSS delivery, WebCore parsing generated pages
No matter which kind of form, to W3C standard “subset” to design, can be more convenient adaptation, with the same should change, in the front wheel emerge in endlessly today, this is the best choice. At the same time, by keeping the simplified subset specification and designing the same rendering process as Native, high performance can surely be achieved.
We can split WebView into two parts: WebCore and JavaScriptCore, focusing on the “W3C standard subset” and “typesetting rendering engine”.
This is in line with Rax’s recent open source project, but IT’s not that I copied this idea. The UI framework I wrote 5 years ago is based on this idea: github.com/myz7656/sma…
I have realized
- CSS styles: 42, standard + part custom
- HTML controls :(standard) div, span, br; (custom) List, Panel, Button, IMG, realwnd
List is used for high performance lists and RecycleView has the same reuse mechanism. Button supports.9 diagrams similar to Android. Realwnd is used to host system controls and has the same function as Flutter PlatformView. (I’m too lazy to document, so I’ll catch up later).
So according to the above design ideas more detailed
- High Performance Scenarios (Lightweight WebCore) : Rendering engine + (templates)
- HTML + CSS
- XML + CSS
- Other DSL combinations
- Dynamic Scenes (Lightweight WebView) : Rendering engine + (Virtual Machine + dynamic Language)
- Lua engine + Lua language
- V8 / JSC engine + JavaScript (big front-end favorite, definitely choose this combination)
- Self-developed VM + language
Overall Architecture Design (Two-stage Architecture)
The rendering engine can realize a “lightweight WebCore” in high-performance scenarios through DOM API calls, and dynamic scenarios can basically be regarded as the implementation of a “lightweight WebView”.
This will be my long-term personal project in my spare time, to continue to promote Smart-UI (after reading the Flutter source code, smart-UI is still too young).
4. Supplementary notes
4.1 Contradiction between performance and dynamics
Essentially, you can’t have dynamics and performance at the same time. Extreme performance requires compilation to binary executables, which are prohibited for Android and iOS. So something that can be delivered dynamically could be
- Intermediate code: executed by virtual machine interpretation on the target platform
- Source code: on the target platform through the virtual machine first compiled into intermediate code, and then explain the execution
Flutter can dynamically deliver intermediate code (modified frame), and the Dart VM loads intermediate code to interpret execution. However, dynamic schemes that connect to Web technologies are usually executed by issuing JavaScript source code and V8 / JavaScriptCore by compiling source code. Either way, the performance will not be great. Is it possible to use AOT mechanism like Android Dalvik VIRTUAL machine to deliver intermediate code and compile it into binary code on the target platform? The V8 engine can optionally be compiled with or without a JIT compiler, which compiles “hot intermediate code” into binary code for execution to improve performance.
V8 Execution Process
Since Flutter can be compiled into binary at compile time, it is theoretically possible to modify the Dart VM to integrate the AOT compiler into the UI framework and compile the intermediate code into binary. I think this route is feasible, but it is expensive and the AOT compiler is included. The package size of the entire UI framework is expected to increase quite a bit (but I haven’t done a deeper understanding of this, or maybe because of my limited understanding, this way is not possible).
4.2 AOT and JIT
Generally speaking, a compiler consists of three parts
- Front end: used to analyze the source code syntax of various languages to form a syntax tree for generating intermediate code (such as Java bytecode, LLVM intermediate code, etc.)
- Optimizer: Optimizes intermediate code to make code more efficient
- Back end: Compiling intermediate code into binary instructions for the target platform (Arm, Armv8, x86, X64, etc.)
LLVM, GCC are all designed in this way, and the advantage of a three-stage compiler is that
- Front end: accept all language rules, as long as it can generate compiler intermediate code, common intermediate code including LLVM IR, Java bytecode
- Backend: Binary code can be generated based on any CPU instruction set
Most virtual machines are designed in this way, but the Java virtual machine (JVM) is an excellent one. As long as it is based on the Java VIRTUAL machine bytecode specification, the bytecode generated by any language can be accepted and executed by the VIRTUAL machine. Does the virtual machine include a compiler back end? Most virtual machines are loaded intermediate code interpretation execution, the core is the “interpreter”, but to improve performance, generally equipped with a “JIT compiler” (here refers to the compiler back end), hot intermediate code to compile, generate binary code, the next run directly run binary code. The same is true of the V8 virtual machine and the Dart virtual machine.
The difference between AOT and JIT is the timing of compiler use
- AOT: Ahead Of Time, all intermediate codes are compiled into binary code before running
- JIT: Just In Time, monitors hot code at runtime and compiles it into binary code
AOT can greatly improve the performance of a program, while JIT can only improve performance to a limited extent. The Android Dalvik VIRTUAL machine also provides AOT capability to compile during App installation, so the installation time is significantly longer.
Personally, I don’t think JIT can improve the performance of the mobile phone. The tracking of hot codes can only take effect when it reaches a certain number of runs. How many times can the App be run to reach this number? Even if you can set this number, how much is appropriate is a bad point to choose. In static languages, a function can be mapped directly to an assembly and then to a binary, because it is clear how much memory is allocated and what the address is. JavaScript itself is a dynamic language, and it could be a function
A parameter <– > A pool code <– > A binary code
B parameter <– > B pool code <– > B binary code
If the JIT is too low, the resulting binaries for different parameters can be very large. JIT performance on the server side makes more sense. Client-side AOT is the best choice for statically typed languages.