HarmonyOS开发实战( Beta5版)小程序场景性能优化开发指导

简介

小程序是一种轻量级的应用,它不需要下载、安装即可使用,用户可以通过扫描二维码或者搜索直接打开使用。小程序运行在特定的平台上,平台提供了小程序的运行环境(运行容器)和一些基础服务(小程序API)。

小程序的架构设计使得它具有快速开发、易于部署、用户使用门槛低等特点,非常适用于实现一些轻量级的应用场景。

图1 经典小程序的双线程架构

经典小程序的双线程架构

小程序的架构如图1所示,其重要组成结构包括小程序API、JSVM Worker、Webview Render三个部分:

小程序API: 它定义了小程序与外部系统或服务交互的方式。小程序平台提供了丰富的API,包括但不限于网络请求、本地存储、设备信息、媒体处理等。开发者可以通过调用这些API来实现小程序的各种功能,如获取用户位置、播放音乐、访问网络资源等。

JSVM Worker: 简称Worker,指的是小程序中逻辑层,它允许开发者在不阻塞主线程的情况下执行耗时的操作,如数据的上传下载、大量数据处理等。比如小程序中的Worker是一个运行在JS线程中的 JavaScript 环境,它与主线程并行执行,互不干扰。

Webview Render: 简称Render, 通常指的是小程序的视图层或渲染层,即小程序的界面是如何被渲染到屏幕上的。小程序的渲染层由小程序框架提供,开发者通过编写WXML(类似 HTML 的标记语言)和WXSS(类似 CSS 的样式表)来定义界面的布局和样式。小程序的渲染引擎会将WXML和WXSS解析并渲染成用户可以看到的界面。

典型业务场景

典型场景

根据人因体验指标,总结当前小程序性能体验的场景如下:

场景分类场景名称简述
小程序页面加载页面加载从原生页面启动小程序,从抬手到小程序首页完全加载完成。
小程序页面中上下滑动浏览场景滑动帧率用户在小程序页面中上下滑动,浏览页面中信息。如用户在外卖小程序页面,上下滑动浏览商家信息。
点击跳转场景点击响应点击跳转,从抬手到页面变化第一帧

场景优化方案

从小程序的场景出发,通过剖析小程序运行时的性能瓶颈, 发现小程序的性能主要体现在以下几个方面:

  1. 组件启动性能:指小程序中各个组件(JSVM、ArkWeb)从初始化到可用状态所需的时间。
  2. 加载性能:涉及小程序从网络或本地加载资源(如页面、图片、脚本等)的速度。
  3. 执行性能:小程序代码执行的效率,包括脚本解析、执行和逻辑处理的速度。
  4. 调用性能:小程序API调用的响应速度和效率,包括与操作系统或硬件交互的性能。
  5. 渲染性能:小程序界面元素渲染到屏幕上的速度和流畅度,直接影响用户体验。

针对各个场景的特征和性能瓶颈,设计了高性能方案,小程序容器可以通过接入高性能方案来解决性能问题。

场景分类场景名称优化方案
小程序页面加载页面加载小程序容器预热
同步JSBridge&AsyncJSB
字节码CodeCache加速
小程序公共资源加载加速
JSVM性能优化
小程序API性能优化
小程序页面中上下滑动浏览场景滑动帧率同步JSBridge&AsyncJSB
JSVM性能优化
小程序API性能优化
点击跳转场景点击响应小程序容器预热
同步JSBridge&AsyncJSB
字节码CodeCache加速
小程序公共资源加载加速
JSVM性能优化
小程序API性能优化

小程序容器预热

原理介绍

小程序启动时,需要创建一个JavaScript引擎,用来执行小程序的逻辑代码,再创建一个WebView,用来渲染小程序的视图。

如果小程序启动时,每次都新创建小程序的运行时环境,其加载性能不可避免的会受到影响,造成用户体验下降。

小程序启动大致流程如图2所示:

图2 小程序启动时序示意图

小程序启动时序示意图

小程序在启动过程中,包含Worker的启动和Render的启动、小程序框架(render.js&service.js)的初始化等步骤,且每个小程序的启动过程都是重复的,因此可以将小程序容器提前创建好,并将公共资源注入到容器中,在小程序启动时,只需要加载小程序的业务代码即可。

场景优化关键点

  1. 预热WebView: 创建离线WebView,并注入小程序视图层的公共资源,并初始化小程序的视图框架。

  2. 预热JSVM: 创建JSVM,并注入小程序逻辑层的公共资源,并初始化小程序逻辑框架。

上述2个关键优化点能带来显著的性能提升。由于所有的关键点都是建立在预热的思路上,提前深度预热小程序运行时容器。下表对各关键点的效果、代价和建议场景进行对比。

关键点收益代价
预热Webview小程序启动性能提升建一个空WebView,多消耗约10M内存
预热JSVM小程序启动性能提升建一个空JSVM,多消耗约5M内存

JSVM的创建与预热较为简单,不涉及UI的复杂状态转换,详细案例可参考《使用JSVM-API接口创建多个引擎执行JS代码并销毁》。

WebView预热方案

鸿蒙化实现方案

本方案适用于WebView预热场景。开发者创建一个新的ArkWeb组件,并在后台注入小程序的公共资源,组件状态为Hidden和InActive,开发者可以在后续使用中按需动态让WebView挂载到ArkUI树上,进行显示。详情请参考《Web组件开发性能提升指导-预渲染优化》。

说明
Web组件数量限制:WebView创建会消耗更多的内存、算力,小程序创建离线WebView组件数量要求小于200个。

性能建议:WebView同样提供了CAPI,推荐在C++侧对WebView进行操作。

通过提前创建WebView控件,进行WebView组件的预热,还可以更进一步,结合后续章节中离线资源免拦截注入,可以实现对小程序框架的预热。

同步JSBridge与异步JSBridge

JSBridge优化解决方案

原理描述

本方案适用于ArkWeb应用侧通信场景,开发者可根据应用架构选择合适的业务通信机制(以下简称JSBridge):

  1. 应用使用ArkTS语言开发,推荐使用ArkWeb在ArkTS提供的runJavaScriptExt接口实现应用侧至前端页面的通信,同时使用registerJavaScriptProxy实现前端页面至应用侧的通信。

  2. 应用使用ArkTS、C++语言混合开发,或本身应用结构较贴近于小程序架构,自带C++侧环境,推荐使用ArkWeb在NDK侧提供的OH_NativeArkWeb_RunJavaScript及OH_NativeArkWeb_RegisterJavaScriptProxy接口实现JSBridge功能。

图3 小程序数据通信架构示意图

小程序数据通信架构示意图

图3为具有普适性的小程序一般架构,其中逻辑层需要应用自带JavaScript运行时,本身已存在C++环境,通过NDK接口可直接在C++环境中完成与视图层(ArkWeb作为渲染器)的通信,无需再返回ArkTS环境调用JSBridge相关接口。

图4 NDK JSBridge方案示意图 

NDK JSBridge方案示意图

NDK JSBridge方案可以解决ArkTS环境的冗余切换,同时允许回调在非UI线程上报,避免造成UI阻塞,如图4所示。

实践案例

【场景一】 使用ArkTS接口实现JSBridge通信

具体实践场景请参考《Web组件开发性能提升指导-JSBridge优化案例一》。

【场景二】 使用NDK接口实现JSBridge通信

图5 使用NDK接口实现JSBridge通信核心流程图

使用NDK接口实现JSBridge通信核心流程图

具体实现场景请参考《Web组件开发性能提升指导-JSBridge优化案例二》。

异步JSBridge调用

原理描述

本方案用于ArkWeb侧调用系统能力场景下,将开发者指定的JSBridge接口调用抛出后,不等待执行结果,以避免在应用主线程负载重时,JSBridge同步调用可能导致Web线程等待IPC时间过长,造成调用阻塞的问题。

优化前优化后

优化前: JSBCall调用应用主线程上运行的业务功能函数时,Web渲染线程需要停下来,等待应用主线程上执行完业务功能函数,才能返回Web渲染线程,Web渲染线程才能继续往下执行。当应用主线程繁忙时,JSB调用需要排队才能得到执行,这时Web渲染线程阻塞的时间变长,性能劣化非常严重。

优化后: JSBCall调用应用主线程上运行的业务功能函数时,Web渲染线程无需等待应用主线程执行业务功能函数,可以继续往下执行,当应用主线程繁忙时,性能提升非常明显。

实践案例

具体实践场景及方案关键点请参考《Web组件开发性能提升指导-异步JSBridge调用》。

CodeCache加速

ArkWeb支持预编译JavaScript生成字节码缓存(Code Cache)

原理描述

本方案用于在页面加载之前提前将即将使用到的JavaScript文件编译成字节码并缓存到本地,在页面首次加载时节省编译时间。

图6 预编译JavaScript核心流程图

预编译JavaScript核心流程图

实践案例

具体实践场景及方案关键点请参考《Web组件开发性能提升指导-预编译JavaScript生成字节码缓存(Code Cache)》。

ArkWeb支持自定义协议的JavaScript生成字节码缓存(Code Cache)

原理描述

本方案用于在页面加载时存在自定义协议的JavaScript,支持其生成字节码缓存到本地,在页面非首次加载时节省编译时间。

实践案例

具体实践场景及方案关键点请参考《Web组件开发性能提升指导-支持自定义协议的JavaScript生成字节码缓存(Code Cache)》。

JSVM支持JavaScript生成字节码缓存(Code Cache)

原理描述

V8引擎在执行JavaScript代码之前需要将JavaScript代码先编译成ByteCode,再执行代码逻辑,而这个编译的耗时,一般占JS执行时间的20~30%,因此,提供JavaScript文件编译成ByteCode的接口,可以加速JSVM的执行速度。

API说明

接口优功能说明
OH_JSVM_CompileScript编译JavaScript代码并返回绑定到当前环境的编译脚本
OH_JSVM_CompileScriptWithOrigin编译JavaScript代码并返回绑定到当前环境的编译脚本,同时传入包括 sourceMapUrl 和源文件名在内的源代码信息,用于处理sourcemap信息
OH_JSVM_CreateCodeCache为编译脚本创建code cache
实践案例

编译及执行JavaScript代码(创建vm,注册function,执行JavaScript,销毁vm):

#include <cstring>
#include <fstream>
#include <string>
#include <vector>// 依赖libjsvm.so
#include "ark_runtime/jsvm.h"using namespace std;static JSVM_Value Hello(JSVM_Env env, JSVM_CallbackInfo info) {JSVM_Value output;void* data = nullptr;OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, nullptr, &data);OH_JSVM_CreateStringUtf8(env, (char*)data, strlen((char*)data), &output);return output;
}static JSVM_CallbackStruct hello_cb = { Hello, (void*)"Hello" };static string srcGlobal = R"JS(
const concat = (...args) => args.reduce((a, b) => a + b);
throw new Error("exception triggered")
)JS";static void RunScript(JSVM_Env env, string& src,bool withOrigin = false,const uint8_t** dataPtr = nullptr,size_t* lengthPtr = nullptr) {JSVM_HandleScope handleScope;OH_JSVM_OpenHandleScope(env, &handleScope);JSVM_Value jsSrc;OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);const uint8_t* data = dataPtr ? *dataPtr : nullptr;size_t length = lengthPtr ? *lengthPtr : 0;bool cacheRejected = true;JSVM_Script script;// 编译js代码if (withOrgin) {JSVM_ScriptOrigin origin {// 以包名 helloworld 为例, 假如存在对应的 sourcemap, source map 的的路径可以是 /data/app/el2/100/base/com.example.helloworld/files/index.js.map.sourceMapurl = "/data/app/el2/100/base/com.example.helloworld/files/index.js.map",// 源文件名字.resourceName = "index.js",// scirpt 在源文件中的起始行列号.resourceLineOffset = 0,.resourceColumnOffset = 0,}OH_JSVM_CompileScriptWithOrigin(env, jsSrc, data, length, true, &cacheRejected, origin, &script);} else {OH_JSVM_CompileScript(env, jsSrc, data, length, true, &cacheRejected, &script);}printf("Code cache is %s\n", cacheRejected ? "rejected" : "used");JSVM_Value result;// 执行js代码OH_JSVM_RunScript(env, script, &result);char resultStr[128];size_t size;OH_JSVM_GetValueStringUtf8(env, result, resultStr, 128, &size);printf("%s\n", resultStr);if (dataPtr && lengthPtr && *dataPtr == nullptr) {// 将js源码编译出的脚本保存到cache,可以避免重复编译,带来性能提升OH_JSVM_CreateCodeCache(env, script, dataPtr, lengthPtr);printf("Code cache created with length = %ld\n", *lengthPtr);}OH_JSVM_CloseHandleScope(env, handleScope);
}

小程序公共资源加载加速

ArkWeb离线资源免拦截注入

原理描述

本方案用于在页面加载之前提前将即将使用到的图片、样式表和脚本资源注入到WebView内存缓存中,在页面首次加载时节省网络请求时间。

图7 资源加速核心流程图

资源加速核心流程图

实践案例

具体实践场景及方案关键点请参考《Web组件开发性能提升指导-离线资源免拦截注入》。

ArkWeb资源拦截替换加速

原理描述

本方案在原本的资源拦截替换接口基础上新增支持了ArrayBuffer格式的入参,开发者无需在应用侧进行ArrayBuffer到String格式的转换,可直接使用ArrayBuffer格式的数据进行拦截替换,避免格式转换和内存拷贝影响性能

实践案例

具体实践场景及方案关键点请参考《Web组件开发性能提升指导-资源拦截替换加速》。

JSVM性能优化

Harmony JSVM-API是基于标准JavaScript引擎提供的一套稳定的ABI,为开发者提供了较为完整的JavaScript引擎能力,包括创建和销毁引擎,执行JavaScript代码,JavaScript/C++交互等关键能力。

开发者可以在应用运行期间直接执行一段动态加载的JavaScript代码。也可以选择将一些对性能、底层系统调用有较高要求的核心功能用C/C++实现并将C++方法注册到JavaScript侧,在JavaScript代码中直接调用,提高应用的执行效率。

创建JSVM Snapshot: 在JSVM预热完成之后,将JSVM的状态保存在磁盘上,第二次加载时,如果小程序的框架代码没有发生变化,直接加载Snapshot文件,无需再次执行小程序框架初始化的动作,提升性能的同时还有降低功耗的效果。

JSVM Snapshot

原理描述

Script虚拟机(JSVM)的快照创建功能,将当前运行时的JavaScript程序状态保存为一个快照文件,这个快照文件包含了当前的堆内存、执行上下文、函数闭包等信息。

动快照: 虚拟机在某个特定时间点的状态快照,包含了当前虚拟机的所有内部状态和数据。通过创建一个启动快照,可以在之后的时间点恢复虚拟机到相同的状态。

机启动快照可以简化一些复杂的编程任务,使得在JSVM中管理和维护虚拟机更加便捷,使程序更加灵活与稳定。

实践案例

API: JVM_CreateSnapshot

#include "napi/native_api.h"
#include "ark_runtime/jsvm.h"
#include <hilog/log.h>
#include <fstream>// CreateAndUseSnapshot注册回调
static JSVM_CallbackStruct param[] = {{.data = nullptr, .callback = CreateAndUseSnapshot},
};
static JSVM_CallbackStruct *method = param;
// CreateAndUseSnapshot方法别名,供JS调用
static JSVM_PropertyDescriptor descriptor[] = {{"createAndUseSnapshot", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};static const int MAX_BUFFER_SIZE = 128;
// CreateHelloString()函数需绑定到JSVM虚拟机, 用于OH_JSVM_CreateSnapshot虚拟机快照的正常创建
static JSVM_Value CreateHelloString(JSVM_Env env, JSVM_CallbackInfo info)
{JSVM_Value outPut;OH_JSVM_CreateStringUtf8(env, "Hello world!", JSVM_AUTO_LENGTH, &outPut);return outPut;
}
// 提供外部引用的方式以便JavaScript环境可以调用绑定的函数
static JSVM_CallbackStruct helloCb = {CreateHelloString, nullptr};
// 外部引用
static intptr_t externals[] = {(intptr_t)&helloCb,0,
};static JSVM_Value RunVMScript(JSVM_Env env, std::string &src)
{// 打开handleScope作用域JSVM_HandleScope handleScope;OH_JSVM_OpenHandleScope(env, &handleScope);JSVM_Value jsStr = nullptr;OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsStr);// 编译JavaScript代码JSVM_Script script;OH_JSVM_CompileScript(env, jsStr, nullptr, 0, true, nullptr, &script);// 执行JavaScript代码JSVM_Value result = nullptr;OH_JSVM_RunScript(env, script, &result);// 关闭handleScope作用域OH_JSVM_CloseHandleScope(env, handleScope);return result;
}
// OH_JSVM_CreateSnapshot的样例方法
static void CreateVMSnapshot() {// 创建JavaScript虚拟机实例,打开虚拟机作用域JSVM_VM vm;JSVM_CreateVMOptions vmOptions;memset(&vmOptions, 0, sizeof(vmOptions));// isForSnapshotting设置该虚拟机是否用于创建快照vmOptions.isForSnapshotting = true;OH_JSVM_CreateVM(&vmOptions, &vm);JSVM_VMScope vmScope;OH_JSVM_OpenVMScope(vm, &vmScope);// 创建JavaScript环境,打开环境作用域JSVM_Env env;// 将native函数注册成JavaScript可调用的方法JSVM_PropertyDescriptor descriptor[] = {{"createHelloString", nullptr, &helloCb, nullptr, nullptr, nullptr, JSVM_DEFAULT},};OH_JSVM_CreateEnv(vm, 1, descriptor, &env);JSVM_EnvScope envScope;OH_JSVM_OpenEnvScope(env, &envScope);// 使用OH_JSVM_CreateSnapshot创建虚拟机的启动快照const char *blobData = nullptr;size_t blobSize = 0;JSVM_Env envs[1] = {env};JSVM_Status status = OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize);if (status == JSVM_OK) {OH_LOG_INFO(LOG_APP, "Test JSVM OH_JSVM_CreateSnapshot success, blobSize = : %{public}ld", blobSize);}// 将snapshot保存到文件中// 保存快照数据,/data/storage/el2/base/files/test_blob.bin为沙箱路径// 以包名为com.example.jsvm为例,实际文件会保存到/data/app/el2/100/base/com.example.jsvm/files/test_blob.binstd::ofstream file("/data/storage/el2/base/files/test_blob.bin",std::ios::out | std::ios::binary | std::ios::trunc);file.write(blobData, blobSize);file.close();// 关闭并销毁环境和虚拟机OH_JSVM_CloseEnvScope(env, envScope);OH_JSVM_DestroyEnv(env);OH_JSVM_CloseVMScope(vm, vmScope);OH_JSVM_DestroyVM(vm);
}
static void RunVMSnapshot() {// blobData的生命周期不能短于vm的生命周期// 从文件中读取snapshotstd::vector<char> blobData;std::ifstream file("/data/storage/el2/base/files/test_blob.bin", std::ios::in | std::ios::binary | std::ios::ate);size_t blobSize = file.tellg();blobData.resize(blobSize);file.seekg(0, std::ios::beg);file.read(blobData.data(), blobSize);file.close();OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot read file blobSize = : %{public}ld", blobSize);// 使用快照数据创建虚拟机实例JSVM_VM vm;JSVM_CreateVMOptions vmOptions;memset(&vmOptions, 0, sizeof(vmOptions));vmOptions.snapshotBlobData = blobData.data();vmOptions.snapshotBlobSize = blobSize;OH_JSVM_CreateVM(&vmOptions, &vm);JSVM_VMScope vmScope;OH_JSVM_OpenVMScope(vm, &vmScope);// 从快照中创建环境envJSVM_Env env;OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env);JSVM_EnvScope envScope;OH_JSVM_OpenEnvScope(env, &envScope);// 执行js脚本,快照记录的env中定义了createHelloString()std::string src = "createHelloString()";JSVM_Value result = RunVMScript(env, src);// 环境关闭前检查脚本运行结果if (result == nullptr) {OH_JSVM_ThrowError(env, nullptr, "Test JSVM RunVMSnapshot-RunVMScript result is nullptr");return;}char str[MAX_BUFFER_SIZE];OH_JSVM_GetValueStringUtf8(env, result, str, MAX_BUFFER_SIZE, nullptr);OH_LOG_INFO(LOG_APP, "Test JSVM RunVMSnapshot-RunVMScript result is: %{public}s", str);// 关闭并销毁环境和虚拟机OH_JSVM_CloseEnvScope(env, envScope);OH_JSVM_DestroyEnv(env);OH_JSVM_CloseVMScope(vm, vmScope);OH_JSVM_DestroyVM(vm);return;
}static JSVM_Value CreateAndUseSnapshot(JSVM_Env env, JSVM_CallbackInfo info)
{// OH_JSVM_Init(&initOptions)需在开发流程中的RunJsVm()中第一次初始化(只能初始化一次)// JSVM_InitOptions initOptions 赋值是在开发流程中完成的// 创建虚拟机快照并将快照保存到文件中CreateVMSnapshot();// snapshot可以记录下特定的js执行环境,可以跨进程通过snapshot快速还原出js执行上下文环境RunVMSnapshot();JSVM_Value result = nullptr;OH_JSVM_CreateInt32(env, 0, &result);return result;
}

JSVM CodeCache

见JSVM支持JavaScript生成字节码缓存(Code Cache)章节

小程序API性能优化

小程序API背景介绍

小程序API是各家大厂小程序生态控制点,通过JS框架解耦对系统的依赖,按照小程序的约束,开发者只能在worker中调用小程序API。

小程序API性能trace点建议

指标类别缩略语全称中文名称解释
逻辑层JSSJS engine StartupJavaScript引擎启动耗时执行JavaScript引擎创建的耗时。
渲染层RSRender StartupWeb引擎启动耗时Webview实例创建的耗时。
逻辑层和渲染层PLTPkg Load Time包加载时间/资源准备耗时把小程序包下载下来,再注入到JavaScript引擎和渲染引擎中的耗时。
逻辑层FFCFirst Frame Calculate首帧计算耗时从开始执行小程序的逻辑到发送给webview第一帧数据之前的耗时。
渲染层FPFirst Paint首次绘制Webview页面首个像素点开始绘制的时刻,无论是否绘制了文本、图片。
渲染层FRFirst Render首帧渲染耗时从接收到第一帧渲染数据到渲染完成时间的耗时。
渲染层LCPLargest Contentful Paint最大有内容绘制Webview渲染面积最大的文本/图片的时刻。
渲染层FFSPFirst Full Screen Paint首次全屏完整绘制从小程序启动到首屏元素铺满的耗时,页面加载结束前最后一次渲染。
JSAPISIWSync Invoke Wait同步调用等待耗时同步调用等待,如getSystemInfoSync等待线程处理的时间。
JSAPISIESync Invoke Execute同步调用执行耗时同步调用执行耗时,如getSystemInfoSync API的执行时间。
JSAPIAIWAsync Invoke Wait异步调用等待耗时如request请求等待线程处理的时间。
JSAPIAICASync Invoke Complete异步调用完成耗时如request API执行时间,从发送到接收完网络数据的时间。
通信RJSRun JavaScript执行JS时间调用webview RunJavaScript接口的耗时。
通信JSBJSB InvokeJSBridge 调用耗时webview通过JS Bridge调用ArkTS/Native API耗时。

通过上述Trace点,可以非常方便的查找出小程序性能的逻辑层、小程序API调用、和渲染层瓶颈点。

小程序API架构建议

小程序API从功能上分类主要有媒体、设备、基础、界面、网络、画布等几百上千不等的API,每个小程序在启动、滑动过程中,Worker有大量并发的小程序API调用,如果将这些API都实现在应用主线程上,将给小程序的性能带来严重的影响,如图8所示。

图8 小程序API调用逻辑

小程序API调用逻辑

在鸿蒙上,将所有的小程序API转发给应用主线程之后,将会造成严重的API调用拥塞的情况。如图9所示:

图9 小程序API调用顺序

小程序API调用顺序

整理一下小程序API调用顺序:

  1. 定位getlocation#297异步API调用发起

  2. 网络Request#298请求异步API调用发起

  3. CanIUse#296同步API调用发起

正常情况下, CanIUse接口耗时1ms,但是在主线程拥塞的情况下,同步调用等待了127ms,等待getlocation执行完成才有机会执行。

因此,建议JSAPI的架构设计如图10所示:

图10 JSAPI调用架构优化示意图

JSAPI调用架构优化示意图

小程序API使用ArkTS编程的注意点

鸿蒙应用采用的声明式编程范式,采用数据驱动的方式改变应用的行为,与android和iOS上的命令式编程范式有很大的区别,鸿蒙上提供了on接口对系统属性进行监听,不必重复调用系统接口获取信息,采用on接口进行监听的方式,在提升性能的同时降低功耗。

如图11与图12所示,每次调用系统接口获取信息,性能劣化严重:

图11 API耗时占比图-函数trace数据

API耗时占比图-函数trace数据

图12 API耗时占比图-函数耗时数据

API耗时占比图-函数耗时数据

针对上图中的三个耗时最大的API:

  1. geoLocationManager.isLocationEnabled

  2. access.getState

  3. wifiManager.isWifiActive

通过查询官方文档,这三个接口都可以通过on接口监听系统变化,如果没有变化,小程序API直接用缓存结果即可,如果有变化,系统会回调应用的监听处理函数,修改缓存值。

因此,在小程序API实现时,应该关注小程序API实现中使用的系统API是否有对应的on接口函数,如果有对应的on接口函数,应该采用on函数优化小程序API性能。

高频小程序API实现方案推荐

异步API名称实现方向
request在C侧实现
getStorage在C侧实现
getStorageInfo在C侧实现
removeStorage在C侧实现
getScreenBrightnessArkTS主线程实现
getSettingon响应式改造
getNetworkTypeon响应式改造
getSystemInfoon响应式改造
getBatteryInfoon响应式改造
getLocationgetLocation
同步API名称实现方向
getSystemInfoSyncon响应式改造
getStorageSync在C侧实现
setStorageSync在C侧实现
getAccountInfoSyncArkTS主线程实现

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

鸿蒙APP开发必备

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/416459.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习笔记5 值得一读,Linux(ubuntu)软件管理,搜索下载安装卸载全部搞定!(上)

本文记录Ubuntu操作系统的软件包管理。 一、背景 整个Linux系统就是大大小小的软件包构成的&#xff0c;在linux系统中&#xff0c;软件的管理非常重要&#xff0c;与其他操作系统不同&#xff0c;linux的软件包管理比较复杂&#xff0c;有时还需要处理软件包之间的冲突。本文…

【电池专题】软包电池封装工序

铝塑膜成型工序冲坑 铝塑膜成型工序,软包电芯可以根据客户的需求设计成不同的尺寸,当外形尺寸设计好后,就需要开具相应的模具,使铝塑膜成型。 成型工序也叫作冲坑,顾名思义,就是用成型模具在加热的情况下,在铝塑膜上冲出一个能够装卷芯的坑,具体的见下图。 …

使用VM创建centos7环境

目录 1、安装VMware Workstation1.1安装VMware Workstation pro 161.2激活VMware Workstation pro 16 2. 创建centos7虚拟机2.1 点击创建新的虚拟机2.2 配置iso镜像2.3开启虚拟机&#xff0c;安装centos7系统 3. 配置网络方法1&#xff1a;方法2&#xff1a;配置静态IP地址 4. …

js逆向--绕过debugger(一)

js逆向--绕过debugger 一、禁用断点二、一律不在此处暂停三、文件替换四、安装最新版火狐浏览器一、禁用断点 首先说明,以下所说的任意一种方法并不适用于所有情况,需要灵活使用。以网站(https://antispider8.scrape.center/page/1)为例,在开发者工具调试区点击停用断点按…

六、桥接模式

桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在将抽象与实现分离&#xff0c;使得两者可以独立变化。通过使用桥接模式&#xff0c;可以避免在多个维度上进行继承&#xff0c;降低代码的复杂度&#xff0c;从而提高系统的可扩展性。 组成…

STM32常用C语言知识总结

目录 一、引言 二、C 语言基础 1.数据类型 2.变量与常量 3.控制结构 4.数组与指针 5.字符串 6. extern变量声明 7.内存管理 三、STM32 中的 C 语言特性 1.位操作 2.寄存器操作 一、引言 STM32 作为一款广泛应用的微控制器&#xff0c;其开发离不开 C 语言的支持。C …

若依系统的学习

若依环境 介绍 ‌若依是一款快速开发平台(低代码)&#xff0c;用于快速构建企业级后台管理系统&#xff0c;它提供了许多常用的功能模块和组件&#xff0c;包括权限管理、代码生成、工作流、消息中心等 官方地址: https://www.ruoyi.vip/ ‌基于Spring Boot和Spring Cloud‌…

vue axios发送post请求跨域解决

跨越解决有两种方案&#xff0c;后端解决&#xff0c;前端解决。后端解决参考Django跨域解决-CSDN博客 该方法之前试着可以的&#xff0c;但是复制到其他电脑上报错&#xff0c;所以改用前端解决 1、main.js做增加如下配置 import axios from axios Vue.prototype.$axios a…

入门数据结构JAVA DS——如何实现简易的单链表(用JAVA实现)

前言 链表&#xff08;Linked List&#xff09;是一种线性数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含两个部分&#xff1a;存储数据的部分和指向下一个节点的指针&#xff08;或引用&#xff09;。链表的结构使得它能够动态地增长和收缩&#xff0c;适合…

【c++】常量周边之const应用:常变量

【c】常量周边&#xff1a;常量概念及定义 承接上文&#xff0c;我们学习了常量的基础知识&#xff0c;在此基础上&#xff0c;本篇文章对于宏定义 #define 和常量 const进行深入学习。 目录 #define 预处理器 const:在常量方面应用 使用技巧 const与指针的结合 const 与 …

我的电脑/资源管理器里无法显示新硬盘?

前情提要 我新&#xff01;买了一个京东京造的SATA3硬盘&#xff0c;一个绿联的SATA3转USB读取 现在我的电脑里只能显示我本地的C盘和D盘&#xff0c;不能显示这个接入的SATA盘。 系统环境&#xff1a;windows11 问题描述 在我的电脑里&#xff0c;只能看到我原本的C和D&…

民宿酒店预订系统V1.0.8

多门店民宿酒店预订管理系统&#xff0c;快速部署属于自己民宿酒店的预订小程序&#xff0c;包含预订、退房、WIFI连接、吐槽、周边信息等功能。提供全部无加密源代码&#xff0c;支持私有化部署。 V1.0.8修复房间预订状态无法筛选的问题 修复房间预订状态无法筛选的问题 修复…

QtAV在windows下编译

官方编译参考 一、源代码下载 git执行操作&#xff1a; git clone https://github.com/wang-bin/QtAV.git cd QtAV && git submodule update --init二、依赖文件下载(ffmpeg) ffmpeg下载 下载完成后&#xff0c;拷贝到QtAV源代码目录&#xff0c;修改根目录名为ff…

MATLAB 计算凹凸多边形的面积(85)

MATLAB 计算凹凸多边形的面积(84) 一、算法介绍二、算法实现1.代码一、算法介绍 计算凹凸多边形的面积,并输出计算结果,可视化 二、算法实现 1.代码 % 设置多边形的顶点坐标 % 这里以一个五边形为例 x = [1, 3, 4

Windows 环境nginx安装使用及目录结构详解

一、 Windows 环境nginx安装及基本使用 1、下载 nginx-1.27.1 最新的主线版本 安装 nginx/Windows&#xff0c;请下载1.27.1最新的主线版本&#xff0c; nginx 的主线分支包含所有已知的修复程序。 2、 解压缩 nginx-1.27.1 版本 nginx/Windows 作为标准控制台应用程序&#x…

uniapp__微信小程序如何对比时间组件框选中框之后的时间大小

1、时间组件框选择时间 2、做判断 if (new Date(selectedDate) < new Date(this.startDate)) {uni.showToast({title: 结束时间不能早于起始时间,icon: none,duration: 2000});return;}console.log(new Date(selectedDate),new Date(this.endDate)); 3、打印出来的时间对比…

#QT 笔记一

重点&#xff1a;面试考试大概率涉及&#xff0c;需要不借助任何资料掌握。掌握&#xff1a;面试考试可能涉及&#xff0c;需要不借助任何资料掌握。熟悉&#xff1a;面试考试可能涉及&#xff0c;可以稍微参考资料掌握。了解&#xff1a;面试考试小概率涉及&#xff0c;面试拔…

【STM32+HAL库】---- 通用定时器PWM输出实现呼吸灯

硬件开发板&#xff1a;STM32G0B1RET6 软件平台&#xff1a;cubemaxkeilVScode1 新建cubemax工程 1.1 配置系统时钟RCC 1.2 配置定时器 找到LED所对应的引脚PA5&#xff0c;选择TIM2_CH1模式 在TIM2中&#xff0c;时钟源选择内部时钟Internal Clock&#xff0c;通道1选择PWM…

Docker中的容器内部无法使用vi命令怎么办?

不知道你是否遇到过,在修改容器内部的配置的时候,有时候会提示vi命令不可用。尝试去安装vi插件,好像也不是很容易,有什么办法可以帮助我们修改这个配置文件呢? 解决办法 这时候,我们就需要用到docker cp 命令了,它可以帮助我们把容器内部的文件复制到宿主机上,也可以将…

服务器文件权限限制写入

1、先查看文件需要的用户权限。 ls -l2、判断自己的账户不具备写入权限 container里面建的文件&#xff0c;需要用户身份是root&#xff0c;如果你不在rootfile里file的话&#xff0c;是无法对需要root权限的文件增删改的。 3、创建container与宿主机共享的文件夹 如果想宿…