Author: wuyawei, Huawei software development engineer

HarmonyOS 2 provides support for two development languages: Java and JavaScript (hereinafter referred to as JS). Students who have been engaged in Android development are familiar with Java. Its multi-threading feature enables parallel execution of multiple tasks and makes full use of hardware resources to develop high-performance applications. On HarmonyOS 2, JS is currently unable to directly create a new Thread like Java. Will the use of JS language to develop HarmonyOS applications encounter a situation where hardware resources cannot be fully utilized?

Although it is currently impossible to directly create a new Thread using JS language, the JS UI framework of HarmonyOS provides a multi-threaded host environment that can help applications develop rich business logic. When developing HarmonyOS 2 applications, in addition to understanding JS threads, which threads do developers need to pay attention to? What is the relationship between these threads? Let us study together.

1. HarmonyOS's JS UI framework

The JS UI framework of HarmonyOS includes the application layer (Application), front-end framework layer (Framework), engine layer (Engine) and platform adaptation layer (Porting Layer), as shown in the following figure:

在这里插入图片描述

• Application

The application layer represents the FA application developed by the developer using the JS UI framework, and the FA application here specifically refers to the JS FA application. https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-js-fa-developing-0000001063300612

• Framework

The front-end framework layer mainly completes the front-end page analysis, and provides MVVM (Model-View-ViewModel) development mode, page routing mechanism and custom components and other capabilities.

• Engine

The engine layer mainly provides capabilities such as animation analysis, DOM (Document Object Model) tree construction, layout calculation, rendering command construction and drawing, and event management.

• Porting Layer

The adaptation layer mainly completes the abstraction of the platform layer, provides abstract interfaces, and can be connected to the system platform. For example: event docking, rendering pipeline docking and system life cycle docking, etc.

2. Thread model of JS UI framework

Every HarmonyOS JS application is loaded and rendered through the JS UI framework. The JS UI framework of HarmonyOS contains 4 threads: JS thread, UI thread, GPU thread, and IO thread, and there will be a type of background task thread outside the JS UI framework.

Among them, GPU thread and IO thread are mainly required for the process of JS UI framework initialization and page loading and rendering. They are dedicated threads inside the JS UI framework, which will not be directly operated by the application, and the application does not need to pay special attention; UI thread, JS thread And the background task thread will be related to the application development code, and the role and relationship of these three threads will be analyzed later.

UI thread : Responsible for drawing and refreshing the application interface, which is the same as the process number of the application and is also called the main thread. If you develop JS+JAVA mixed programming ( https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-fa-calls-pa-mechanism-0000001050022401), you need to pay special attention to JAVA PA (Particle Ability)'s onStart/onConnect and other Ability life cycle callbacks are run on the main thread. If time-consuming operations are performed on these life cycle callbacks, the drawing refresh of the JS UI will be stuck.
JS thread : The JS code of the application will be parsed and executed by the JS engine and run on the JS thread. At present, all the JS code seen in our project will be executed on the only JS thread in this process.
background task thread : This is a general term for background threads outside the JS UI framework. It does not only refer to a thread, nor is it unique. It contains related threads such as the execution thread of onRemoteRequest() business logic in Java PA, the file operation API, and the internal implementation of the network access API.

Let's take a look at the relationship between these three threads that need to be paid attention to in application development by combining the test code.

Third, the relationship between JS thread and UI thread

In order to verify the relationship between the JS thread and the UI thread, we have prepared an experimental Demo. The main code and the log of the running process are as follows:

First, we create a HelloWorld project with Empty Ability (JS) template in the IDE, and add Log in the life cycle and button response callback method to observe the thread situation. The application life cycle in the newly created app.js already has Log by default, and no additional addition is required.

We need to add HiLog printing to the onStart/onTouchEvent callback function in the automatically created MainAbility.java:

HiLog.info(LABEL_LOG, "MainAbility::onStart");

HiLog.info(LABEL_LOG, "MainAbility::onTouchEvent");

We only need to add the log onInit in the index.js file of the main interface:

CoffeeScript

console.info('page.default onInit');

Then add a button and a progress component that will always be animated in index.hml:

<button id='button1' onclick="onButtonClick">I'm a button</button>

<progress type="circular"/>

Finally, add button click response events and Log in index.js, and try to sleep to block the js thread:

function sleep(delay) {

for (var t = Date.now(); Date.now() - t <= delay; );

}

onButtonClick() {

console.info('onButtonClick begin');

sleep(1000);

console.info('onButtonClick end');

}

We run the application and click the button once, and we will find that the progress component animation will not be paused because onButtonClick is blocked for 1 second. Let's analyze the Log in this process together:

15:30:07.323 15870-15870/com.blancwu.test I 01100/MainAbility: MainAbility::onStart

15:30:07.342 15870-18938/com.blancwu.test I 03B00/JSApp: app Log: AceApplication onCreate

15:30:07.352 15870-18938/com.blancwu.test I 03B00/JSApp: app Log: page.default onInit

15:30:31.006 15870-15870/com.blancwu.test I 01100/MainAbility: MainAbility::onTouchEvent

15:30:31.041 15870-15870/com.blancwu.test I 01100/MainAbility: MainAbility::onTouchEvent

15:30:31.104 15870-15870/com.blancwu.test I 01100/MainAbility: MainAbility::onTouchEvent

15:30:31.106 15870-15870/com.blancwu.test I 01100/MainAbility: MainAbility::onTouchEvent

15:30:31.112 15870-18938/com.blancwu.test I 03B00/JSApp: app Log: onButtonClick begin

15:30:32.113 15870-18938/com.blancwu.test I 03B00/JSApp: app Log: onButtonClick end

From the output log, the time point is followed by the process number and thread number where the code line of our execution log is located. The logs we just added are all under the process 15870, under this process there are 15870 threads and 18938 threads. 15870 is the same as the process number, which is the UI thread we are talking about; all the logs we add to the .js file will be printed on the 18938 thread, this is the JS thread.

在这里插入图片描述

When the application is initialized, first enter the onStart life cycle callback of MainAbility.java, and then enter the JS code logic such as AceApplication and Page; after the application is initialized, the progress component animation will be continuously refreshed on the UI thread. When the user clicks the button, onButtonClick is triggered When blocking for 1 second, because only the JS thread is blocked, the animation refresh of the progress component on the UI thread will not have any effect, and it will continue to refresh. So we can determine that the mutual call between the JS thread and the UI thread should be done through some kind of message mechanism, rather than a blocking call.

Fourth, the relationship between JS threads and background task threads

The JS UI framework provides a mechanism for JS FA (Feature Ability) to call Java PA (Particle Ability). This mechanism provides a channel to transfer method calls, process data returns, and subscribe to event reporting. Java PA runs on an independent The background task thread can support the multi-threaded business logic of application development. We also make a Demo to verify the relationship between JS threads and Java PA threads:

Based on the previous Demo, we modified the JS code of onButtonClick, pulled up and called a Java PA named ServiceAbility through FeatureAbility.callAbility, and got the returned result:

var action = {};

action.bundleName = 'com.blancwu.test';

action.abilityName = 'com.blancwu.test.ServiceAbility';

action.messageCode = 1001;

action.abilityType = 0;

action.syncOption = 0;

console.info('FeatureAbility.callAbility begin' + JSON.stringify(action));

FeatureAbility.callAbility(action).then(function (value) {

console.info('FeatureAbility.callAbility async result ' + JSON.stringify(value));

})

console.info('FeatureAbility.callAbility end' + JSON.stringify(action));

Increase the Log output in ServiceAbility's onRemoteRequest, and sleep for 1 second, in order to observe the relationship between the thread situation and:

@Override

public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {

HiLog.info(LABEL_LOG, "onRemoteRequest begin " + code);

if (code == 1001) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

Map<String, Object> result = new HashMap<String, Object>();

result.put("result", 1);

reply.writeString(ZSONObject.toZSONString(result));

}

HiLog.info(LABEL_LOG, "onRemoteRequest end " + code);

return super.onRemoteRequest(code, data, reply, option);

}

After the above code is completed, we execute it, and the animation of the progress component will also not be interrupted. The Log obtained is as follows:

06-25 13:31:48.090 4133-5887/com.blancwu.test I 03B00/JSApp: app Log: FeatureAbility.callAbility begin{"bundleName":"com.blancwu.test","abilityName":"com.blancwu.test.ServiceAbility","messageCode":1001,"abilityType":0,"syncOption":0}

06-25 13:31:48.094 4133-5887/com.blancwu.test I 03B00/JSApp: app Log: FeatureAbility.callAbility end{"bundleName":"com.blancwu.test","abilityName":"com.blancwu.test.ServiceAbility","messageCode":1001,"abilityType":0,"syncOption":0}

06-25 13:31:48.112 4133-4133/com.blancwu.test E 01100/ServiceAbility: [8187916a4418bed, 399b373, f521b3] ServiceAbility::onStart

06-25 13:31:48.126 4133-5837/com.blancwu.test I 01100/ServiceAbility: [8187916a4418bed, 171378f, 385abb1] onRemoteRequest begin 1079135572

06-25 13:31:48.126 4133-5837/com.blancwu.test I 01100/ServiceAbility: [8187916a4418bed, 171378f, 385abb1] onRemoteRequest end 1079135572

06-25 13:31:48.126 4133-5837/com.blancwu.test I 00000/RemoteObject: [8187916a4418bed, 171378f, 385abb1] Java onRemoteRequest called

06-25 13:31:48.143 4133-5837/com.blancwu.test I 01100/ServiceAbility: onRemoteRequest begin 1001

06-25 13:31:49.145 4133-5837/com.blancwu.test I 01100/ServiceAbility: onRemoteRequest end 1001

06-25 13:31:49.145 4133-5837/com.blancwu.test I 00000/RemoteObject: Java onRemoteRequest called

06-25 13:31:49.151 4133-5887/com.blancwu.test I 03B00/JSApp: app Log: FeatureAbility.callAbility async result "{\"result\":1}"

The entire execution process can be described as follows:

在这里插入图片描述

We observe that the main process (UI thread) number of this run is 4133, the JS code is executed in the JS thread (5887), and the Java PA responds to onRemoteRequest to be executed in another background task thread (5837). Through Log, we can see that even if onRemoteRequst blocks the background task thread for 1s, it will not affect the execution of the JS thread and the refresh of the animation on the main thread (UI thread), so that the tasks on the JS thread and the background task thread are processed in parallel.

Five, JS asynchronous mechanism

The above observed the relationship between JS threads and other threads in application development from the perspective of code experiments, then how does JS thread communicate asynchronously with other threads? Let's first look at the mechanism in the traditional browser environment:

在这里插入图片描述

In the above figure, the function calls in the JS thread will exist in the stack. The functions in the stack can call the WebAPIs provided by the browser environment, including DOM, ajax, timeout and other APIs, which will be provided in the browser environment Another external thread is executed, and the corresponding callback events (such as onClick, onLoad, onDone) will be added to the task queue (callback queue) after the execution is completed. When the code in the stack is executed, that is, after the stack is emptied, the JS thread will take out the next task in the task queue through the event loop for execution, and so on to complete the entire program execution. For a more specific mechanism, please see the article by Mr. Ruan Yifeng introducing JS EventLoop.

JS EventLoop

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

HarmonyOS's JS UI framework also follows the above-mentioned most basic EventLoop scheduling mechanism, and provides more mechanisms and APIs so that business logic can be executed in external threads; including the Java PA mechanism mentioned above and the support for asynchronous not yet mentioned Callback system capability API. Among them, the system capability API that supports asynchronous callbacks includes file system operations and network operations. Interested students can try it in a similar way to our experimental Demo.

file system operation API reference

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-file-storage-0000000000629445

VI. Future Outlook

At present, the best way to achieve multi-threading in HarmonyOS JS application is to call Java PA through mixed programming, but it cannot support pure JS application development multi-threaded business. Pure JS applications can only use the asynchronous API provided by the framework at present, so these asynchronous Can API solve various complex scenarios?

JS thread plus asynchronous API can solve the problem of single I/O blocking very well, but if you encounter a large number of I/O events, such as batch deleting a large number of files, launching a large number of asynchronous tasks through the for loop, it will also reduce the execution efficiency. Even block the execution of other asynchronous tasks. And if you want to use the JS language to develop computationally intensive tasks, it cannot be done on the only JS thread.

At this time, a real JS multi-threaded processing mechanism is needed. Although HarmonyOS 2 does not currently support it, in the future HarmonyOS will consider planning to provide support for WebWorker mechanism similar to HTML5, support the development of multi-threaded JS code, and provide it for application development. People have more room to play.


看点
19 声望4 粉丝