HarmonyOS 2提供了两种利用开发语言:Java和JS。Java线程个性可能让多任务并行,充分利用硬件资源开发出高性能的利用。而JS却是一个单线程语言,无奈像Java一样创立新的Thread,用JS语言开发是否会导致硬件资源无奈充分利用的状况呢?
本文给大家介绍“ACE JS的单线程异步机制”就是解决这个问题的。然而,说到 “单线程”与“异步”,大家可能会比拟纳闷,因为单线程和异步在概念上是抵触的,单线程无奈做到多任务并发,也就不会存在异步这种通信机制。
的确,JS语言自身是无奈实现异步的,然而ACE JS框架却提供了多线程的宿主环境,通过音讯通信机制让JS语言有了异步的属性,上面咱们来详细描述其原理。
ACE开发框架
应用JS开发HarmonyOS利用,应用的开发框架名为ACE(Ability Cross-Platform Environment),该框架实用于手机、平板、智慧屏、智慧表、车机等设施,具备“一次开发,多端部署”的能力。
ACE框架包含应用层(Application)、前端框架层(Framework)、引擎层(Engine)和平台适配层(Porting Layer),如下图所示:
●Application
应用层示意开发者应用JS UI框架开发的FA利用,这里的FA利用特指JS FA利用。
●Framework
前端框架层次要实现前端页面解析,以及提供MVVM(Model-View-ViewModel)开发模式、页面路由机制和自定义组件等能力。
●Engine
引擎层次要提供动画解析、DOM(Document Object Model)树构建、布局计算、渲染命令构建与绘制、事件治理等能力。
●Porting Layer
适配层次要实现对平台层进行形象,提供形象接口,能够对接到零碎平台。比方:事件对接、渲染管线对接和零碎生命周期对接等。
ACE开发框架的线程模型
每个HarmonyOS JS利用,都是通过上图所示的ACE开发框架进行加载渲染的。ACE开发框架蕴含了JS线程、UI线程、GPU线程、IO线程,并且在ACE框架外还会存在一类后台任务线程。
其中GPU线程与IO线程次要是ACE框架初始化与页面加载渲染的过程须要的,为ACE框架外部的专有线程,不会被利用间接操作到,利用不须要特地关注;UI线程、JS线程和后台任务线程会与利用开发代码相干,前面着重剖析这三个线程的作用和关系。
●UI线程:负责利用界面的绘制刷新,与利用的过程号雷同,又叫主线程。如果开发JS+JAVA的混合编程,JAVA PA(Particle Ability)的onStart/onConnect等Ability生命周期回调便是运行在主线程,若在这些生命周期回调上执行耗时操作则会导致JS UI的绘制刷新卡住。
●JS线程:利用的JS代码会被JS引擎解析执行,并运行在JS线程上,而JS又是单线程语言,所以目前咱们工程中看到的所有的JS代码都会执行在这个过程下惟一的JS线程上。
●后台任务线程:这里是对ACE框架内部的后盾线程的一个统称,并不单指一个线程,也并不惟一。后台任务线程蕴含了Java PA线程、文件操作API、网络拜访API外部实现等相干线程。
上面咱们联合测试代码来看一下这3个线程之间的关系。
JS线程与UI线程的关系
为了验证JS线程与UI线程的关系,咱们筹备了一个试验性质的Demo,次要代码以及运行过程的Log如下:
首先咱们在IDE建设一个Empty Ablity(JS)模板的HelloWorld工程,在生命周期、按钮响应回调办法里减少Log以察看线程状况。刚创立的app.js中Application生命周期默认曾经有Log,无需额定增加。
咱们只须要在主界面index.js文件中onInit减少日志:
console.info('page.default onInit');
而后在index.hml中减少一个button以及会始终进行动画的progress组件:
<button id='button1' onclick="onButtonClick">I'm a button</button>
<progress type="circular"/>
最初在index.js中减少按钮点击响应事件以及Log,并且尝试sleep阻塞js线程:
function sleep(delay) {
for (var t = Date.now(); Date.now() - t <= delay; );
}
onButtonClick() {
console.info('onButtonClick begin');
sleep(1000);
console.info('onButtonClick end');
}
将利用运行起来,点击两次按钮,失去如下Log:
从输入的Log中,咱们能够看到这个JS FA过程号为22592,也就是说UI线程是22592;生命周期回调以及按钮响应均在24077线程,这个就是JS线程,所以JS线程与UI线程不是同一个线程。
并且咱们尝试通过sleep办法阻塞JS线程,想察看JS线程阻塞是否会影响到UI线程的刷新。最终得出的论断是无论JS线程sleep多长时间,UI界面上的progress组件动画始终会一直刷新,按钮也会有按压成果变动,所以咱们能够揣测JS线程与UI线程的互相调用应该是通过某种音讯机制实现的,而不是阻塞式的调用。
JS线程与后台任务线程的关系
ACE JS框架提供了JS FA(Feature Ability)调用Java PA(Particle Ability)的机制,该机制提供了一种通道来传递办法调用、解决数据返回以及订阅事件上报。咱们同样制作一个Demo来验证JS线程与Java PA线程的关系:
在JS中,咱们通过FeatureAbility.callAbility拉起并调用了名为一个类名为ServiceAbility的Java PA,并拿到返回后果:
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));
在ServiceAbility的onRemoteRequest中减少Log输入,并sleep 1秒钟,以便察看线程状况与之间关系:
@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);
}
以上代码实现后,咱们进行执行,失去的Log如下:
咱们察看到本次运行主过程(UI线程)号为4133,JS代码执行在JS线程5887,Java PA响应onRemoteRequest执行在另一个后台任务线程5837。通过Log咱们看到onRemoteRequst即便阻塞了后台任务线程1s也不会影响JS线程的并行执行以及主线程(UI线程)上动画的刷新,做到了JS线程与后台任务线程异步地执行事务。
JS线程的异步机制
下面从代码试验角度观察到了JS线程与其余线程的异步关系,那么JS线程是怎么解决来自其余多个线程的调用的呢?咱们先来看一下传统的浏览器环境下的机制:
上图中,JS线程中的函数调用会存在于栈(stack)中,栈中的函数能够调用浏览器环境提供的WebAPIs,蕴含了DOM、ajax、timeout等API,这些API会在浏览器环境提供的另外一个内部线程执行,执行实现后会在工作队列(callback queue)中退出对应的回调事件(如onClick、onLoad、onDone)。当栈中的代码执行结束,即栈清空后,JS线程又会通过event loop取出工作队列中的下一个工作进行执行,以此类推实现整个的程序执行。更具体的机制能够去看阮一峰老师介绍JS EventLoop的文章:
● JS EventLoop介绍
http://www.ruanyifeng.com/blo...
HarmonyOS ACE开发框架同样遵循上述最根本的EventLoop调度机制,并且提供了更多的机制和API,让业务逻辑能够在内部线程执行,蕴含了下面提到的Java PA以及异步回调的零碎能力API。其中,异步回调的零碎能力API蕴含如文件系统操作和网络操作等,具体大家能够依照咱们试验Demo的办法去尝试一下。
● 参考
https://developer.harmonyos.c...
将来倒退的瞻望
目前ACE JS利用内实现多线程的最佳形式是通过混合编程调用Java PA形式,但将来纯JS利用肯定会越来越多,那么,只反对单线程的JS ACE框架的异步API能解决各种简单场景的问题吗?
单线程的JS加上异步API可能很好解决单个I/O阻塞的问题,然而如果遇到大量的I/O事件,比方批删除大量文件,通过for循环发动了大量异步工作,也会升高执行效率,甚至阻塞其余异步工作的执行。并且如果要应用JS语言开发计算密集型的工作,也无奈在惟一的JS线程上进行。
这时就须要一个真正的JS多线程解决机制了,尽管目前HarmonyOS 2还未反对,但将来HarmonyOS会思考布局出与HTML5相似提供反对WebWorker机制,反对开发出多线程的JS代码,提供给利用开发者更多的施展空间。