Home  >  Article  >  Web Front-end  >  Let’s take a look at Hongmeng JavaScript GUI technology stack

Let’s take a look at Hongmeng JavaScript GUI technology stack

coldplay.xixi
coldplay.xixiforward
2020-09-14 13:28:552642browse
<p>Let’s take a look at Hongmeng JavaScript GUI technology stack

<p>Related learning recommendations: javascript video tutorial

<p>As we all know, the newly open source “Hongmeng 2.0” uses JavaScript as IoT Framework language for application development. This marks that JavaScript has once again become a hot topic at the news network level after SpaceX took off. It would be a pity to only use Yin and Yang for such a good opportunity. As a popular science, this article will not use a magnifying glass to find out the flaws in the code to find faults. Instead, I hope to explain in a popular way what the GUI it supports is all about. As long as you have a general understanding of computer basics, there should be no obstacles to reading this article.

<p>We already know that on "Hongmeng 2.0", developers only need to write JavaScript business logic in the form of Vue components, and they can be rendered into UI interfaces on embedded hardware such as smart watches. What core modules need to be involved in this process? Which of these modules are self-developed, and which ones use ready-made open source projects? It is divided into three abstract layers from top to bottom to introduce:

  • JS framework layer, which can be understood as a greatly simplified Vue-style JavaScript framework
  • JS engine and runtime layer, can be understood as a greatly simplified WebKit-style runtime
  • Graphics rendering layer, can be understood as a greatly simplified Skia-style graphics drawing library
<p>These three abstraction layers form a GUI technology stack for embedded hardware. Different from many public opinions that shout "unclear/unfathomable", I personally think that at least for the GUI part, any front-line developer in China who has been exposed to the current mainstream Hybrid cross-end solutions or JS runtime development can easily start from the source code. Set out to understand it. Let’s do some interpretation and analysis of it layer by layer.

JS Framework Layer

<p>From the top-level perspective, if you want to use "Hongmeng 2.0" to render a dynamic text, you only need to write the following HML (XML-like) format code:

<!-- hello.hml --><text onclick="boil">{{hello}}</text>复制代码
<p>Then write JavaScript like this in the same level directory:

// hello.jsexport default {  data: {    hello: 'PPT'
  },
  boil() {    this.hello = '核武器';
  }
}复制代码
<p> In this way, as long as the text is clicked, the boil method will be called to make PPT change Into nuclear weapons.

<p>What happened behind this? Students who are familiar with Vue 2.0 should immediately think of the following things:

  • requires a preprocessing mechanism for XML to convert it into a nested function structure in JS. In this way, you only need to do a simple eval at runtime, and you can use JS to generate a UI that conforms to the XML structure.
  • An event mechanism is required so that the corresponding callback can be executed when the onclick event is triggered.
  • Requires a data hijacking mechanism so that the corresponding callback can be executed when assigning a value to this.hello.
  • Need to be able to update UI object controls in callbacks.
<p>How are these things achieved? To put it simply, it is this:

  • XML preprocessing relies on the ready-made NPM open source package to convert the onclick attribute in XML into a JS object. Attribute field.
  • Event registration and triggering are implemented directly in C. The onclick attribute of the JS object obtained in the previous step will be checked and registered in C, which is equivalent to all components being native.
  • Data hijacking mechanism is implemented in JS and is a ViewModel (a few hundred lines in size) based on Object.defineProperty.
  • The update of the UI control will be implemented by calling the native method of C in the JS callback automatically executed by the ViewModel. This part is completely done implicitly and does not expose the document.createElement-style standardized API.
<p> Since a large number of capabilities in common JS frameworks are directly implemented into C, the entire GUI technology stack is implemented using pure JavaScript (mainly see ace_lite_jsfwk under the warehouse core/index.js, observer.js and subject.js), which is equivalent to having and only one function:

<p>A ViewModel that can be watched.

<p>As for the implementation complexity and quality of the pure JS framework part, objectively speaking, if it is a personal amateur work, it can be used as a good bonus in the school recruitment interview.

JS engine and runtime layer

<p>After understanding the JS framework layer, we can either think that "Hongmeng 2.0" has chosen to deeply customize the highly simplified Vue into C, or we can think that It implements a supporting front-end framework tightly around a highly simplified (and private) DOM. Therefore, if we want to continue to explore the principles of this GUI, we must enter its C part and understand the implementation of its JS engine and runtime layer.

<p>What are the differences and connections between JS engine and runtime? JS engines generally only need to comply with the ECMA-262 specification, which does not define any platform APIs with "side effects". From setTimeout to document.getElementById to console.log to fs.readFile, these functions that can perform actual IO operations are all It needs to be provided by the runtime of "glue the engine API and platform API together". The principle of the runtime itself is not complicated. For example, in my personal article "From JS Engine to JS Runtime", you can see how to build a runtime yourself with the help of the ready-made QuickJS engine.

<p>So how is the JS runtime built in "Hongmeng 2.0"? There are several key points:

  • The JS engine chose JerryScript, an embedded JS engine developed by Samsung.
  • Each XML tag component in the shape of <text> and <p> corresponds to a C Component class bound to JerryScript, such as TextComponent and pComponent etc.
  • In addition to UI native objects, there are also a series of built-in modules prefixed with @system in JS, which provide platform capabilities such as Router / Audio / File available in JS (See ohos_module_config.h).
<p> Router is particularly worth mentioning here. It is very different from the implementation principles of common Web platform routing such as vue-router. It is specially customized deeply during runtime (see router_module.cpp, js_router.cpp and js_page_state_machine.cpp). Simply put, this "routing" is implemented like this:

  • Call the router.replace native method of switching pages in JS and enter C. In
  • C, load the new page JS according to the new page URI path (such as pages/detail), create a new page state machine instance, and switch it to the Init state.
  • In the Init process of the new state machine, call the JS engine to eval the JS code of the new page and obtain the ViewModel of the new page.
  • Append route parameters to the ViewModel and destroy the old state machine and the JS objects on it.
<p>So we can find that the so-called "switch route" here is actually closer to the "refresh page" of the web browser. So can we think that the capabilities of this JS runtime can already benchmark the WebKit-level browser kernel?

<p>Of course it’s still far from it. Compared with WebKit, it does not support the parsing of HTML and CSS (both will be parsed and converted into JS with the same execution effect during the development phase), nor does it have the challenge of continuously dynamically loading, parsing and executing resources in the browser (small The program is nothing more than a few local static JS files). As for typesetting, layout and rendering, there is naturally a big gap, which will be mentioned in the last section.

<p>In addition, I believe many students will be curious about the JerryScript engine. This section concludes by sharing some personal information on this issue.

<p>JerryScript engine is a JS interpreter specially implemented for embedded hardware and only supports the ES5.1 standard. In QuickJS Benchmark, you can see their performance comparison results:

Let’s take a look at Hongmeng JavaScript GUI technology stack
<p>You can see that in terms of performance, JerryScript is significantly weaker in engines without JIT For QuickJS and Hermes. If compared with V8 with JIT turned on, it will even be two orders of magnitude slower. Therefore, this is a very specific engine for low-end devices. If you need to support basic libraries that are standard in medium and large front-end projects such as React and Vue (or even their corresponding family buckets), you may still need to use a more powerful engine.

<p> Regarding the use of JerryScript, RT-Thread founder @midnightbear is undoubtedly the one who has heavy application experience in the same scenario. The smart watch they developed in cooperation with a domestic first-tier manufacturer used JerryScript to implement the UI. The current product is available now It's about to be launched. Some feedback from their team on the use of JerryScript is also consistent with the above evaluation. In summary, it is as follows:

  • JerryScript 在体积和内存占用上,相比 QuickJS 有更好的表现。
  • JerryScript 的稳定性弱于 QuickJS,有一些难以绕过的问题。
  • JerryScript 面对稍大(1M 以上)的 JS 代码库,就有些力不从心了。
<p>那么师出名门的 QuickJS 和 Facebook 的 Hermes,是否就是无 JIT 式 JS 引擎的下一代标杆了吗?倒也未必如此。这方面可以参考个人的知乎回答:随着 TypeScript 继续普及,会不会出现直接跑 TypeScript 的运行时?这里提到的微软为教育项目 MakeCode 研发的 Static TypeScript,就相当有潜力成为下一代的高性能 JS 系语言环境。通过限定 TypeScript 的静态强类型子集并为其搭建工具链,STS 可以做到无需 JIT 也能接近 V8 的性能水平,同时内存占用比 V8 少两个数量级。这使得 STS 不光能用于开发普通 app 这类 IO 密集的应用,还能顺利在嵌入式硬件上开发小游戏这类更偏计算密集(需逐帧更新渲染)的应用,在工程能力上是一项很大的突破。

<p>所以说,当「鸿蒙 2.0」还需要熟练开发者勉强搭建出环境跑通 Hello World 时,微软已经让上百万小朋友都能用 TypeScript 在网页里给教学用的掌上游戏机写小游戏入门编程了。这里没什么唱反调的意思,只希望提醒一下我们在为国产「里程碑」欢呼时,也要清醒地看到业界前沿的动向,仅此而已。

图形绘制层

<p>理解 JS 运行时之后,还剩最后一个问题,即 JS 运行时中的各种 Component 对象,是如何被绘制为手表等设备上的像素的呢?

<p>这就涉及「鸿蒙 2.0」中的另一个 graphic_lite 仓库了。可以认为,这里才是真正执行实际绘制的 GUI。像之前的 TextComponent 等原生组件,都会对应到这里的某种图形库 View。它以一种相当经典的方式,在 C++ 层实现并提供了「Canvas 风格的立即模式 GUI」和「DOM 风格的保留模式 GUI」两套 API 体系(对于立即模式和保留模式 GUI 的区别与联系,可参见个人这篇 IMGUI 科普回答)。概括说来,这个图形子系统的要点大致如下:

  • 图形库提供了 UIView 这个 C++ 控件基类,其中有一系列形如 OnClick / OnLongPress / OnDrag 的虚函数。基本每种 JS 中可用的原生 Component 类,都对应于一种 UIView 的子类。
  • 除了各种定制化 View 之外,它还开放了一系列形如 DrawLine / DrawCurve / DrawText 等命令式的绘制方法。
  • 这个图形库具备名为 GFX 的 GPU 加速模块,但它目前似乎只有象征性的 FillArea 矩形单色填充能力。
<p>在基础 UI 控件方面,不难找到一些值得一提的自研模块特性:

  • 支持了简易的 RecycleView 长列表。
  • 支持了简易的 Flex 布局。
  • 支持了内部的 Invalidate 脏标记更新机制。
<p>至于 2D UI 渲染中的几项关键能力,则基本可分为路径、位图和文字三类。这个图形库在这几个方面都有涉及,最后简单介绍一下。

<p>首先对于位图,这个图形库依赖了 libpnglibjpeg 做图像解码,然后即可使用内存中的 bitmap 图像做绘制。

<p>然后对于路径,这个图形库自己实现了各种 CPU 中的像素绘制方法,典型的例子就是这个贝塞尔曲线的绘制源码:

void DrawCurve::DrawCubicBezier(const Point& start, const Point& control1, const Point& control2, const Point& end,    const Rect& mask, int16_t width, const ColorType& color, OpacityType opacity)
{    if (width == 0 || opacity == OPA_TRANSPARENT) {        return;
    }

    Point prePoint = start;    for (int16_t t = 1; t <= INTERPOLATION_RANGE; t++) {
        Point point;
        point.x = Interpolation::GetBezierInterpolation(t, start.x, control1.x, control2.x, end.x);
        point.y = Interpolation::GetBezierInterpolation(t, start.y, control1.y, control2.y, end.y);        if (prePoint.x == point.x && prePoint.y == point.y) {            continue;
        }

        DrawLine::Draw(prePoint, point, mask, width, color, opacity);
        prePoint = point;
    }
}复制代码
<p>基于高中的数学知识,我们不难明白这种曲线是如何绘制出来的:取足够多的点(也就是那个默认 1000 的 INTERPOLATION_RANGE)作为插值输入,逐点计算出曲线表达式的 XY 坐标,然后直接修改像素位置所在的 framebuffer 内存即可。这种教科书式的实现是最经典的,不过如果要拿它对标 Skia 里的黑魔法,还是不要勉为其难了吧。

<p>最后对于文字的绘制,会涉及一些字体解析、定位、RTL和折行等方面的处理。这部分实际上也是组合使用了一些业界通用的开源基础库来实现的。比如对于「牢」这个字,就可以找到图形库的这么几个开源依赖,它们各自扮演不同的角色:

  • harfbuzz - 用来告诉调用者,应该把「牢」的 glyph 字形放在哪里。
  • freetype - 从宋体、黑体等字体文件中解码出「牢」的 glyph 字形,将其光栅化为像素。
  • icu - 处理 Unicode 中许多奇葩的特殊情况,这块个人不了解,略过。
<p>到这里,我们就可以理出一个非常概括性的渲染流程了:

  • Execute code like this.hello = 'PPT' in JS to trigger dependency tracking.
  • JS dependency tracking callback triggers the native function and updates the Component component state of C.
  • Component updates the state of its bound UIView subclass and triggers graphics library updates.
  • The graphics library updates the pixel status in memory and completes drawing.
<p>This is my personal interpretation of the GUI technology stack of "Hongmeng 2.0". Due to limited time, I did not delve further, and (civilized) criticisms and corrections are welcome.

Summary

<p>Special statement: This subjective review is only for the current GUI framework of “Hongmeng 2.0”, please do not misinterpret it at will.

<p> Regarding the highlights of "Hongmeng 2.0" in the GUI part, I can personally think of these:

  • It does have pragmatic code (but it is completely different from the PPT introduction back then).
  • It is not a WebView shell, the layout and drawing are done by myself.
  • You don’t need to have computer knowledge beyond the undergraduate level to read and understand smoothly.
<p>As for the obvious (not just some ugly lines of code) deficiencies or problems, it seems that there are currently the following:

  • JS Framework Layer
    • No basic inter-component communication (such as props/emit, etc.) capabilities
    • No basic custom component capabilities
    • No State management capabilities other than basic dependency tracking
  • JS engine and runtime layer
    • Standard support is too low to run next-generation front-ends that require Proxy such as Vue 3.0 The framework
    • The performance level is weak and it is difficult to support medium and large JS applications
    • There is no open DOM-style object model API, which is not conducive to the upper layer smoothing the differences
  • Graphics Rendering Layer
    • No substantial GPU acceleration available
    • No advanced rendering capabilities such as SVG and rich text
    • Canvas Complete Low degree, lack of state stack and many APIs
<p> It seems that there are many shortcomings, but would you accuse the car of not having a jet engine? For scenarios of different complexity, there are naturally different optimal architecture designs. At present, it seems that this design is indeed very suitable for embedded hardware and simple "small programs" scenarios. But if we look at it according to the so-called "distributed full-scenario cross-platform" requirements, the complexity of this architecture is completely incomparable to modern web browsers or iOS and Android GUIs. If you want to implement it on a mobile phone, you will almost certainly need to add a large number of complex modules and undergo substantial architectural evolution and redesign.

<p>Of course, car manufacturers will not say that they build airplanes, right?

<p>In short, this is indeed a plate of mapo tofu made by myself, but it is not the Manchu-Han banquet as some people say.

<p>Finally, a personal subjective comment:

<p>First of all, this GUI technology stack has reached the mainstream level that can be obtained when assembling and drawing on open source products. However, in terms of performance and expressiveness, there is still an order of magnitude generational gap between its core modules and industry-cutting-edge industry-university-research cutting-edge solutions such as Microsoft MakeCode.

<p>Secondly, don’t think of it as Rocket Science, which requires precision calculations by a large number of experts - I am not belittling independent research and development, but I sincerely hope that everyone can understand, "I can also actually participate in this matter !" The operating system and GUI are not so mysterious. There are many domestic mature open source products available for learning, use and contribution (by the way, RT-Thread, which is very easy to experience and also made in China, is recommended as an early adopter). After all, only if you truly understand what a product is technically like, will it be less likely to be manipulated by people with ulterior motives, right?

<p>Finally, for all front-end developers who are familiar with JavaScript, Why do you still laugh at Hongmeng in a weird way? Hongmeng is the wealth code of JavaScript in China! JavaScript is adopted by a "national weapon" like Hongmeng, which can greatly enhance the front-end's road confidence, theoretical confidence, cultural confidence and technology stack confidence. As long as we combine splicing and self-research in this way, we can gain a high reputation across the country in one fell swoop. This road is really fascinating (whispering)

<p>We must unite and vigorously promote and publicize JavaScript’s status as a nuclear deterrent in the competition between great powers must rise to a level where as long as you say you can write JavaScript, everyone will respect you - as long as you are a front-end programmer, you can jump in line when buying a ticket, give up your seat when taking a bus, and get a room. You can have sex for free...the good times are coming!

<p> Do you want to be a pillar of the country? Let’s write JavaScript!

<p>No more words, I am going to work hard to rejuvenate the country!

<p> If you want to know more about programming learning, please pay attention to the php training column!

The above is the detailed content of Let’s take a look at Hongmeng JavaScript GUI technology stack. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.im. If there is any infringement, please contact admin@php.cn delete