0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

OpenHarmony源碼剖析之ACE(JavaScript運(yùn)行環(huán)境初始化)

OpenAtom OpenHarmony ? 來源:51CTO ? 作者:張亮亮 ? 2021-11-18 10:40 ? 次閱讀

張亮亮

深圳開鴻數(shù)字產(chǎn)業(yè)發(fā)展有限公司

簡(jiǎn)介

JS UI 框架引擎ACE全稱 Ability Cross-platform Environment,是 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)上的UI框架。ACE:結(jié)合了 OpenHarmony 系統(tǒng)的基礎(chǔ)組件 Ability,開源 jsframework 框架,開源 js 引擎 quickjs,開源跨平臺(tái) UI 框架 flutter,開源渲染引擎 skia 以及各種平臺(tái)能力 API 等共同構(gòu)筑了 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng) javacript 應(yīng)用開發(fā)的基礎(chǔ)。

1.1 OpenHarmony 架構(gòu)圖

9b9230c6-47d2-11ec-b939-dac502259ad0.png

1.2 ACE UI框架引擎圖

9cadf030-47d2-11ec-b939-dac502259ad0.png

1.3 ACE 主要構(gòu)成

1. JavaScript前端框架

目前 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)采用主流的類 Web 范式,對(duì)開源的 Weex 框架中的 jsframework 做定制化,采用 ts 開發(fā),主要包括編程模型 MVVM、組件、API、頁(yè)面路由以及事件處理。

2. JavaScript引擎

目前 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)使用的是開源 quickjs 引擎,提供 JS 語言運(yùn)行時(shí)和執(zhí)行上下文,提供 js 的解析和 jsframework 的加載。

3. 中間轉(zhuǎn)換層

中間轉(zhuǎn)換層也就是 JS 橋接層,實(shí)現(xiàn)前端開發(fā)框架到 UI 后端引擎和 JS 引擎的對(duì)接。

4. 聲明式UI后端引擎

C++構(gòu)建的UI后端引擎,包括 UI 組件、布局視圖、動(dòng)畫事件、自繪制選軟管線。

5. 渲染引擎

目前 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)復(fù)用了開源跨平臺(tái) UI 框架 flutter 引擎提供基礎(chǔ)的圖形渲染能力。

6. 平臺(tái)適配層

目前 OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)的適配層完成了 OpenHarmony 平臺(tái)和 IDE 的 previewer 的適配,將平臺(tái)依賴聚焦到平臺(tái)相關(guān)的畫布、通用線程以及事件處理機(jī)制等少數(shù)接口上,為跨平臺(tái)提供相應(yīng)的基礎(chǔ)設(shè)施,實(shí)現(xiàn)跨平臺(tái)一致化的 UI 渲染。

7. 能力擴(kuò)展層

為擴(kuò)展 ACE 能力提供的插件機(jī)制,平臺(tái)其他子系統(tǒng)可以利用插件機(jī)制開發(fā)相關(guān)能力的 js 接口,為應(yīng)用層提供相應(yīng)的能力支持。通過 napi 提供引擎無關(guān)的插件實(shí)現(xiàn)機(jī)制,保證接口的 ABI 兼容性。

基礎(chǔ)知識(shí)

2.1 代碼結(jié)構(gòu)
/foundation/ace/ace_engine├── adapter                       # 平臺(tái)適配目錄│   ├── common|   ├── ohos                      # ohos平臺(tái)適配目錄│   └── preview                   # IDE preview平臺(tái)適配目錄├── frameworks                    # 框架代碼│   ├── base                      # 基礎(chǔ)庫(kù)│   ├── bridge                    # 前后端對(duì)接層│   └── core                      # 聲明式UI后端引擎目錄/third_party/jsframework          # JavaScript前端框架/third_party/quickjs              # JavaScript引擎/third_party/flutter#flutterengine提供跨平臺(tái)自渲染引擎

2.2 ACE框架類圖

9ce025a0-47d2-11ec-b939-dac502259ad0.png

(點(diǎn)擊圖片查看高清大圖) 2.3 線程模型

ACE JS 應(yīng)用啟動(dòng)時(shí)會(huì)創(chuàng)建一系列線程,形成獨(dú)立的線程模型,以實(shí)現(xiàn)高性能的渲染流程。

Platform線程:當(dāng)前平臺(tái)的主線程,也就是應(yīng)用的主線程,主要負(fù)責(zé)平臺(tái)層的交互、應(yīng)用生命周期以及窗口環(huán)境的創(chuàng)建。

JS線程:JS 前端框架的執(zhí)行線程,應(yīng)用的 JS 邏輯以及應(yīng)用 UI 界面的解析構(gòu)建都在該線程執(zhí)行。

UI線程:引擎的核心線程,組件樹的構(gòu)建以及整個(gè)渲染管線的核心邏輯都在該線程:包括渲染樹的構(gòu)建、布局、繪制以及動(dòng)畫調(diào)度。

GPU線程:現(xiàn)代的渲染引擎,為了充分發(fā)揮硬件性能,都支持 GPU 硬件加速,在該線程上,會(huì)通過系統(tǒng)的窗口句柄,創(chuàng)建 GPU 加速的 OpenGL 環(huán)境,負(fù)責(zé)將整個(gè)渲染樹的內(nèi)容光柵化,直接將每一幀的內(nèi)容渲染合成到該窗口的 Surface 上并送顯。

IO線程:主要為了異步的文件 IO 讀寫,同時(shí)該線程會(huì)創(chuàng)建一個(gè)離屏的 GL 環(huán)境,這個(gè)環(huán)境和 GPU 線程的 GL 環(huán)境是同一個(gè)共享組,可以共享資源,圖片資源解碼的內(nèi)容可直接在該線程上傳生成 GPU 紋理,實(shí)現(xiàn)更高效的圖片渲染。

Javascript運(yùn)行環(huán)境初始化

3.1 時(shí)序圖

9d28c008-47d2-11ec-b939-dac502259ad0.png

(點(diǎn)擊圖片查看高清大圖)

3.2 源碼解析

1.OnStart()

  • AceAbility繼承自Ability,當(dāng)應(yīng)用啟動(dòng)時(shí)首先應(yīng)用程序框架會(huì)調(diào)用AceAbility的生命周期函數(shù)OnStart();

  • 通過Ability的api獲取Hap包的路徑,通過讀取配置文件manifest.json獲取應(yīng)用程序配置的前端的類型;

  • 當(dāng)前我們只關(guān)注JS前端,目前支持的前端類型包括enum class FrontendType { JSON, JS, JS_CARD, DECLARATIVE_JS };

  • 根據(jù)前端類型調(diào)用ACE核心聚合類AceContainer的靜態(tài)方法CreateContainer,這個(gè)類是ACE框架平臺(tái)適配層的核心類,接下來的前端核心類和JS引擎的創(chuàng)建都是在其中完成的。

//foundationaceace_engineadapterpreviewentranceace_ability.cppvoid AceAbility::OnStart(const Want& want){    ...        //獲取打包的js bundle文件,取出配置文件,獲取前端類型    auto packagePathStr = GetBundleCodePath();    auto moduleInfo = GetHapModuleInfo();    if (moduleInfo != nullptr) {        packagePathStr += "/" + moduleInfo->name + "/";    }    FrontendType frontendType = GetFrontendTypeFromManifest(packagePathStr);
    // create container    //創(chuàng)建AceContainer:內(nèi)部初始化時(shí)創(chuàng)建了js線程,load了js engine,創(chuàng)建了JsFrontend    Platform::CreateContainer(        abilityId_, frontendType, this,        std::make_unique([this]() {            TerminateAbility();        }));    ...    ...
    //運(yùn)行page    Platform::RunPage(        abilityId_, Platform::GetContainer(abilityId_)->GeneratePageId(),        parsedPageUrl, want.GetStringParam(START_PARAMS_KEY));
    ...}
2. CreateContainer
  • 在AceContainer::CreateContainer中,首先創(chuàng)建了AceContainer對(duì)象;

  • 在構(gòu)造函數(shù)中創(chuàng)建了FlutterTaskerExecutor對(duì)象用于多線程的任務(wù)管理;

  • 此處主要關(guān)注JS線程的創(chuàng)建和初始化,在InitJsThread()中創(chuàng)建了JS線程并獲取保存了jsRunner_用于JS任務(wù)的派發(fā);

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::CreateContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback){    auto aceContainer = AceType::MakeRefPtr(instanceId, type, aceAbility, std::move(callback));    AceEngine::Get().AddContainer(instanceId, aceContainer);    auto front = aceContainer->GetFrontend();    if (front) {        front->UpdateState(Frontend::ON_CREATE);        front->SetJsMessageDispatcher(aceContainer);    }}
AceContainer::AceContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback) : instanceId_(instanceId), type_(type), aceAbility_(aceAbility){    ACE_DCHECK(callback);    //創(chuàng)建和初始化FlutterTaskerExecutor用于封裝管理Flutter ACE中涉及的多個(gè)線程:platform,UI,JS,GPU,IO,統(tǒng)一post任務(wù)到各線程執(zhí)行    auto flutterTaskExecutor = Referenced::MakeRefPtr();    //初始化platform線程,將flutter platform線程的TaskerRunner適配到ohos平臺(tái)主線程的EventRunner    flutterTaskExecutor->InitPlatformThread();    //初始化JS線程,這個(gè)線程用于解析JS,不歸flutter管理,因此是單獨(dú)在ACE里使用的    flutterTaskExecutor->InitJsThread();    //taskExector_封裝了所有線程任務(wù)調(diào)度的接口,因此會(huì)傳給Frontend用于JS前端解析任務(wù)和PipelineContext后端渲染UI和GPU IO相關(guān)    taskExecutor_ = flutterTaskExecutor;    if (type_ != FrontendType::DECLARATIVE_JS) {        //zll:初始化前端        InitializeFrontend();    }
    platformEventCallback_ = std::move(callback);}
void FlutterTaskExecutor::InitJsThread(bool newThread){    //創(chuàng)建并初始化JS線程,獲取保存js線程的TaskRunner    //JS線程是ACE平臺(tái)特有,不通過flutter創(chuàng)建管理    if (newThread) {        jsThread_ = std::make_unique(GenJsThreadName());        jsRunner_ = jsThread_->GetTaskRunner();    } else {        jsRunner_ = uiRunner_;    }}

3. JsFrontend

  • 完成JS線程的初始化后,如果前端類型不是DECLARATIVE_JS,會(huì)調(diào)用InitializeFrontend()對(duì)前端進(jìn)行初始化。

  • 首先創(chuàng)建前端對(duì)象,F(xiàn)rontend::Create定義在js_frontend.cpp中,創(chuàng)建的是JsFrontend實(shí)例;

  • 然后通過JsEngineLoader::Get()動(dòng)態(tài)加載QjsEngineLoader;

  • 再通過QjsEngineLoader創(chuàng)建QjsEngine并設(shè)置給JsFrontend;最后對(duì)JsFrontend對(duì)象做初始化;

  • JsFrontend是ACE框架從后端進(jìn)入前端的唯一入口,AceAbility、AceContainer和JsFrontend是一一對(duì)應(yīng)的關(guān)系;

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::InitializeFrontend(){    if (type_ == FrontendType::JS) {        //目前Frontend::Create定義在js_frontend.cpp中,創(chuàng)建的是JsFrontend實(shí)例        frontend_ = Frontend::Create();        auto jsFrontend = AceType::DynamicCast(frontend_);        //創(chuàng)建并初始化js engine,此處是通過dlopen加載的qjs engine管理對(duì)象        jsFrontend->SetJsEngine(Framework::Get().CreateJsEngine(instanceId_));        ...    } else if (type_ == FrontendType::DECLARATIVE_JS) {        ...    } else {        ...    }    ACE_DCHECK(frontend_);    //初始化前端和js engine    frontend_->Initialize(type_, taskExecutor_);}
4. QjsEngine
  • 接下來我們繼續(xù)分析一下JS引擎管理對(duì)象的創(chuàng)建;

  • 首先通過dlopen動(dòng)態(tài)加載libace_engine_qjs.z.so通過入口函數(shù)創(chuàng)建獲取QjsEngineLoader單例對(duì)象;

  • 然后通過QjsEngineLoader::CreateJsEngine()創(chuàng)建QjsEngine;

//foundationaceace_engineframeworksridgejs_frontendenginecommonjs_engine_loader.cpp//"libace_engine_qjs.z.so"動(dòng)態(tài)庫(kù)的入口,在qjs_engine_loader.cpp中定義constexpr char JS_ENGINE_ENTRY[] = "OHOS_ACE_GetJsEngineLoader";constexpr char QUICK_JS_ENGINE_SHARED_LIB[] = "libace_engine_qjs.z.so";...const char* GetSharedLibrary(){    return QUICK_JS_ENGINE_SHARED_LIB;}JsEngineLoader& GetJsEngineLoader(const char* sharedLibrary){    void* handle = dlopen(sharedLibrary, RTLD_LAZY);    ...    //    auto loader = reinterpret_cast(entry());    ...
    return *loader;}...//通過加載動(dòng)態(tài)鏈接庫(kù)的形式獲取qjs橋接模塊的入口函數(shù)并創(chuàng)建QjsEngineLoaderJsEngineLoader& JsEngineLoader::Get(){    static JsEngineLoader& instance = GetJsEngineLoader(GetSharedLibrary());    return instance;}
//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine_loader.cppRefPtr QjsEngineLoader::CreateJsEngine(int32_t instanceId) const{    return AceType::MakeRefPtr(instanceId);}
5. JS線程
  • 在完成了QjsEngine的創(chuàng)建并設(shè)置給JsFrontend后,調(diào)用JsFrontend::Initialize();

  • 這里主要完成了FrontendDelegateImpl對(duì)象的創(chuàng)建和初始化將對(duì)JS引擎的相關(guān)操作委派給這個(gè)對(duì)象;

  • 以及Post JS引擎初始化的任務(wù)到JS線程的TaskRunner的message queue;

//foundationaceace_engineframeworksridgejs_frontendjs_frontend.cppbool JsFrontend::Initialize(FrontendType type, const RefPtr& taskExecutor){    LOGI("JsFrontend initialize begin.");    type_ = type;    ACE_DCHECK(type_ == FrontendType::JS);    //創(chuàng)建并初始化FrontendDelegate對(duì)象,具體實(shí)現(xiàn)為FrontendDelegateImpl    InitializeFrontendDelegate(taskExecutor);    //在JS線程初始化js engine,真正的啟動(dòng)JS引擎運(yùn)行時(shí)并創(chuàng)建上下文    taskExecutor->PostTask(        [weakEngine = WeakPtr(jsEngine_), delegate = delegate_] {            auto jsEngine = weakEngine.Upgrade();            if (!jsEngine) {                return;            }            jsEngine->Initialize(delegate);        },        TaskExecutor::JS);
    LOGI("JsFrontend initialize end.");    return true;}
6. jsframework
  • 在JS線程執(zhí)行QjsEngine對(duì)象的初始化,初始化JS運(yùn)行環(huán)境;

  • 初始化JS引擎運(yùn)行時(shí)上下文和初始化JavaScript框架層jsframework;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppbool QjsEngine::Initialize(const RefPtr& delegate){    ACE_SCOPED_TRACE("QjsEngine::Initialize");    LOGI("Initialize");
    JSRuntime* runtime = nullptr;    JSContext* context = nullptr;
    // put JS_NewContext as early as possible to make stack_top in context    // closer to the top stack frame pointer of JS thread.    runtime = JS_NewRuntime();    if (runtime != nullptr) {        context = JS_NewContext(runtime);    }
    ...
    engineInstance_ = AceType::MakeRefPtr(delegate, instanceId_);    return engineInstance_->InitJsEnv(runtime, context);}
bool QjsEngineInstance::InitJsEnv(JSRuntime* runtime, JSContext* context){    ...    context_ = context;    //1.初始化js運(yùn)行時(shí),上下文    if (!InitJsContext(context_, MAX_STACK_SIZE, instanceId_, this)) {        LOGE("Qjs cannot allocate JS context");        EventReport::JS_ENGINE_INIT_ERR);        JS_FreeRuntime(runtime_);        return false;    }    ...    //2.加載JS Framework,初始化JS前端框架    //加載jsframework,js_framework和js_framework_size是quickjs編譯器編譯jsframework的ts生成的c文件    //quickjs通過JS_ReadObject讀取生成的cbytecode,并通過JS_EvalFunction(ctx, obj)執(zhí)行相應(yīng)的函數(shù)    //在這里最終調(diào)用的函數(shù)是jsframework/runtime/preparation/index.ts中的initFramework()函數(shù)    JSValue retVal = LoadJsFramework(GetQjsContext(), js_framework, js_framework_size, instanceId_);    bool result = JS_IsException(retVal) ? false : true;    if (context) {        JS_FreeValue(context, retVal);    }    ...
    return result;}
7. ACE模塊
  • 初始化JS引擎運(yùn)行時(shí)上下文是在InitJsContext完成;

  • 其中初始化Ace模塊并將模塊導(dǎo)入JS運(yùn)行時(shí)上下文中,為jsframework框架層提供了ACE功能相關(guān)的接口;

  • jsframework可以通過調(diào)用ACE模塊的接口完成Page上Dom元素到后端聲明式UI元素節(jié)點(diǎn)的創(chuàng)建;

  • 同時(shí)往JS運(yùn)行時(shí)上下文全局對(duì)象掛載了日志打印的函數(shù)用于對(duì)接平臺(tái)日志打印功能;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cpp//ace模塊向js context暴露的函數(shù),(js函數(shù)名,參數(shù)個(gè)數(shù),對(duì)應(yīng)的C函數(shù))const JSCFunctionListEntry JS_ACE_FUNCS[] = {    JS_CFUNC_DEF_CPP("domCreateBody", 5, JsDomCreateBody),    JS_CFUNC_DEF_CPP("domAddElement", 9, JsDomAddElement),    JS_CFUNC_DEF_CPP("updateElementAttrs", 3, JsUpdateElementAttrs),    JS_CFUNC_DEF_CPP("updateElementStyles", 3, JsUpdateElementStyles),    JS_CFUNC_DEF_CPP("onCreateFinish", 0, JsOnCreateFinish),    JS_CFUNC_DEF_CPP("onUpdateFinish", 0, JsOnUpdateFinish),    JS_CFUNC_DEF_CPP("removeElement", 2, JsRemoveElement),    JS_CFUNC_DEF_CPP("callNative", 1, JsCallNative),    JS_CFUNC_DEF_CPP("callComponent", 3, JsCallComponent),    JS_CFUNC_DEF_CPP("loadIntl", 0, JsLoadIntl),    JS_CFUNC_DEF_CPP("loadLocaleData", 0, JsLoadLocaleData),#ifdef ENABLE_JS_DEBUG    JS_CFUNC_DEF_CPP("compileAndRunBundle", 4, JsCompileAndRunBundle),#endif};...
bool InitJsContext(JSContext* ctx, size_t maxStackSize, int32_t instanceId, const QjsEngineInstance* qjsEngineInstance){    ...        //將ace模塊注入到上下文中,使得jsframework可以通過注冊(cè)的接口調(diào)用ace的相關(guān)功能    // Inject ace native functions module    InitAceModules(ctx);
    JSValue globalObj, perfUtil;    globalObj = JS_GetGlobalObject(ctx);    perfUtil = JS_NewObject(ctx);
    InitJsConsoleObject(ctx, globalObj);
    JS_SetPropertyStr(ctx, perfUtil, "printlog", JS_NewCFunction(ctx, JsPerfPrint, "printlog", 0));    JS_SetPropertyStr(ctx, perfUtil, "sleep", JS_NewCFunction(ctx, JsPerfSleep, "sleep", 1));    JS_SetPropertyStr(ctx, perfUtil, "begin", JS_NewCFunction(ctx, JsPerfBegin, "begin", 1));    JS_SetPropertyStr(ctx, perfUtil, "end", JS_NewCFunction(ctx, JsPerfEnd, "end", 1));    JS_SetPropertyStr(ctx, globalObj, "perfutil", perfUtil);
    ...
    JSValue hiView;    hiView = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, hiView, "report", JS_NewCFunction(ctx, JSHiViewReport, "report", 2));    JS_SetPropertyStr(ctx, globalObj, "hiView", hiView);
    JSValue i18nPluralRules;    i18nPluralRules = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, i18nPluralRules, "select", JS_NewCFunction(ctx, JsPluralRulesFormat, "select", 1));    JS_SetPropertyStr(ctx, globalObj, "i18nPluralRules", i18nPluralRules);        //將ace模塊導(dǎo)入到cxt指定的js 上下文中    const char* str = "import * as ace from 'ace';
"                      "var global = globalThis;
"                      "global.ace = ace;
"#ifdef ENABLE_JS_DEBUG                      "global.compileAndRunBundle = ace.compileAndRunBundle;
"#endif                      "global.callNative = ace.callNative;
";
    if (JS_CALL_FAIL == CallEvalBuf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE, instanceId)) {        LOGW("Qjs created JS context but failed to init Ace modules!");    }
    JS_FreeValue(ctx, globalObj);    return true;}

8. 初始化完成

  • 完成JS運(yùn)行時(shí)上下文初始化之后,緊接著加載初始化jsframework,為JS應(yīng)用程序提供javascript應(yīng)用框架;

  • 這個(gè)地方使用quickjs的運(yùn)行bytecode的方法,在編譯時(shí)通過qjsc(quickjs編譯器)將jsframework編譯成c文件;

  • c文件的內(nèi)容就是一個(gè)bytecode的組數(shù)和數(shù)組大小,指定了jsframework的入口函數(shù);

  • 在這里對(duì)應(yīng)jsframework/runtime/preparation/index.ts 中的initFramework()完成jsframework的初始化;

  • jsframework初始化完成的工作主要包括掛載到j(luò)s運(yùn)行時(shí)上下文全局對(duì)象上提供給native調(diào)用的jsframework函數(shù),注冊(cè)到j(luò)sframework的ACE提供的模塊及其中的方法和jsframework提供的與native一一對(duì)應(yīng)的組件及其方法;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppJSValue LoadJsFramework(JSContext* ctx, const uint8_t buf[], const uint32_t bufSize, int32_t instanceId){    ACE_SCOPED_TRACE("LoadJsFramework");
    LOGI("Qjs loading JS framework");    //等同于調(diào)用jsframework/runtime/preparation/index.ts 中的initFramework()    JSValue ret = CallReadObject(ctx, buf, bufSize, true, instanceId);    if (JS_IsException(ret)) {        LOGD("Qjs loading JSFramework failed!");        QjsUtils::JsStdDumpErrorAce(ctx, JsErrorType::LOAD_JS_FRAMEWORK_ERROR, instanceId);    }
    return ret;}
//third_partyjsframework
untimepreparationinit.tsexport function initFramework(): void {  for (const serviceName in i18n) {    service.register(serviceName, i18n[serviceName]);  }  for (const serviceName in dpi) {    service.register(serviceName, dpi[serviceName]);  }  //jsframework提供的可供Ace native在QjsEngine對(duì)象中調(diào)用的TS方法  const globalMethods: GlobalInterface = {    'createInstance': globalApi.createInstance,    'registerModules': globalApi.registerModules,    'appDestroy': globalApi.appDestroy,    'appError': globalApi.appError,    'destroyInstance': globalApi.destroyInstance,    'getRoot': globalApi.getRoot,    'callJS': globalApi.callJS  };  //注冊(cè)modules,這些modules是ACE module提供的,調(diào)用這些模塊的方法,會(huì)通過調(diào)用注冊(cè)到qjs_engine的ace模塊中的callNative方法  //會(huì)最終通過ace module的callNative調(diào)用到qjs_engine中的JsCallNative-->JsHandleModule-->然后調(diào)用對(duì)應(yīng)的native方法  // registerModules and registerComponents  ModulesInfo.forEach(modules => {    globalMethods['registerModules'](modules);  });    //注冊(cè)components組件,對(duì)組件方法的調(diào)用,最終會(huì)通過ace module的callComponent調(diào)用到qjs_engine中的JsCallComponent  ComponentsInfo.forEach((name) => {    if (name && name.type && name.methods) {      NativeElementClassFactory.createNativeElementClass(        name.type,        name.methods      );    }  });  //全局方法,這些方法可以被Qjs engine通過JS_GetPropertyStr(ctx, globalObj, "methodNamge")獲取并調(diào)用,從而實(shí)現(xiàn)了從native到j(luò)s的調(diào)用  for (const methodName in globalMethods) {    global[methodName] = (...args: any) => {      const res: any = globalMethods[methodName](...args);      if (res instanceof Error) {        Log.error(res.toString());      }      return res;    };  }}

總結(jié)

以上內(nèi)容首先對(duì) OpenHarmony 標(biāo)準(zhǔn)系統(tǒng)上 JS UI 框架引擎 ACE 的邏輯架構(gòu)及相關(guān)模塊進(jìn)行了簡(jiǎn)單的介紹,給出了 ACE 架構(gòu)中相關(guān)模塊涉及的部分類的類圖,結(jié)合本次重點(diǎn)分析的 Javascript 運(yùn)行環(huán)境初始化的時(shí)序圖詳細(xì)分析了 Javascript 運(yùn)行環(huán)境初始化的整個(gè)流程。

本文首發(fā)自:https://harmonyos.51cto.com/posts/7908
編輯:jq


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JS
    JS
    +關(guān)注

    關(guān)注

    0

    文章

    75

    瀏覽量

    17983
  • ui
    ui
    +關(guān)注

    關(guān)注

    0

    文章

    202

    瀏覽量

    21290
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3548

    瀏覽量

    15743

原文標(biāo)題:OpenHarmony源碼解析之ACE(JavaScript運(yùn)行環(huán)境初始化)

文章出處:【微信號(hào):gh_e4f28cfa3159,微信公眾號(hào):OpenAtom OpenHarmony】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    字符型、指針型等變量等該如何初始化

     對(duì)于數(shù)值類型的變量往往初始化為0,但對(duì)于其他類型的變量,如字符型、指針型等變量等該如何初始化呢?
    的頭像 發(fā)表于 03-18 11:02 ?903次閱讀

    MCU單片機(jī)GPIO初始化該按什么順序配置?為什么初始化時(shí)有電平跳變?

    GPIO初始化時(shí)有時(shí)鐘配置、模式配置、輸出配置、復(fù)用配置,那么在編寫初始化代碼時(shí),到底該按什么順序執(zhí)行呢?如果順序不當(dāng)那初始化過程可能會(huì)出現(xiàn)短暫的電平跳變。
    的頭像 發(fā)表于 02-22 11:07 ?1172次閱讀
    MCU單片機(jī)GPIO<b class='flag-5'>初始化</b>該按什么順序配置?為什么<b class='flag-5'>初始化</b>時(shí)有電平跳變?

    OpenHarmony NAPI 框架介紹

    環(huán)境中的 JS 變量與方法。 OpenHarmony 中的 NAPI OpenAtom OpenHarmony(以下簡(jiǎn)稱 “OpenHarmony”)應(yīng)用層基于
    的頭像 發(fā)表于 02-01 17:34 ?540次閱讀
    <b class='flag-5'>OpenHarmony</b> <b class='flag-5'>之</b> NAPI 框架介紹

    串口初始化一般是初始化哪些內(nèi)容

    串口初始化是指在使用串口進(jìn)行數(shù)據(jù)通信之前,對(duì)串口進(jìn)行一系列的設(shè)置和配置,以確保串口能夠正常工作。串口初始化的內(nèi)容主要包括以下幾個(gè)方面: 串口硬件設(shè)置:首先,需要確定要使用的串口是哪一個(gè),通常計(jì)算機(jī)
    的頭像 發(fā)表于 01-04 09:39 ?2703次閱讀

    labview運(yùn)行后如何初始化

    LabVIEW是一款強(qiáng)大的圖形編程軟件,在運(yùn)行之前通常需要進(jìn)行一些初始化操作。本文將詳細(xì)介紹LabVIEW運(yùn)行前的初始化過程,并提供了一些
    的頭像 發(fā)表于 12-28 17:24 ?2073次閱讀

    自動(dòng)初始化機(jī)制原理詳解

    自動(dòng)初始化機(jī)制是指初始化函數(shù)不需要被顯式調(diào)用,只需要在函數(shù)定義處通過宏定義的方式進(jìn)行申明,就會(huì)在系統(tǒng)啟動(dòng)過程中被執(zhí)行。這篇文章就來探索一下其中的奧秘, 簡(jiǎn)單理解其原理!
    的頭像 發(fā)表于 12-16 09:33 ?828次閱讀
    自動(dòng)<b class='flag-5'>初始化</b>機(jī)制原理詳解

    C語言編程時(shí),各種類型的變量該如何初始化?

    C語言編程時(shí),各種類型的變量該如何初始化? 在C語言中,每個(gè)變量都需要在使用之前進(jìn)行初始化。初始化是為變量分配內(nèi)存空間并賦予初始值的過程。C語言提供了不同的
    的頭像 發(fā)表于 12-07 13:53 ?941次閱讀

    教程分享!OpenHarmonyNAPI框架介紹

    是 C++語言實(shí)現(xiàn)的,這些接口可以幫助 C++代碼創(chuàng)建 JS 變量,或訪問 JavaScript 運(yùn)行環(huán)境中的 JS 變量與方法。 OpenHarmony 中的 NAPI OpenAt
    的頭像 發(fā)表于 11-30 12:15 ?1157次閱讀
    教程分享!<b class='flag-5'>OpenHarmony</b><b class='flag-5'>之</b>NAPI框架介紹

    javascript運(yùn)行環(huán)境有哪些

    JavaScript 是一種廣泛應(yīng)用于網(wǎng)頁(yè)開發(fā)的編程語言,它可以在不同的運(yùn)行環(huán)境運(yùn)行。以下是一些常見的 JavaScript
    的頭像 發(fā)表于 11-27 16:11 ?2228次閱讀

    實(shí)戰(zhàn)經(jīng)驗(yàn) | Keil、IAR、CubeIDE 中變量不被初始化方法

    關(guān)鍵詞:不被初始化,編譯環(huán)境 目錄預(yù)覽 1、前言 2、IAR 實(shí)現(xiàn)變量不初始化方法 3、Keil 實(shí)現(xiàn)變量不被初始化方法 4、CubeIDE 實(shí)現(xiàn)變量不
    的頭像 發(fā)表于 11-24 18:05 ?3025次閱讀

    OpenHarmonyNAPI框架介紹

    。 可以看到,NAPI 接口本身是 C++語言實(shí)現(xiàn)的,這些接口可以幫助 C++代碼創(chuàng)建 JS 變量,或訪問 JavaScript 運(yùn)行環(huán)境中的 JS 變量與方法。 OpenHarmony
    發(fā)表于 11-23 15:36

    如何在博途環(huán)境下載但不重新初始化數(shù)據(jù)塊呢?

    現(xiàn)場(chǎng)設(shè)備運(yùn)行過程中有時(shí)候我們需要更改在線數(shù)據(jù)塊的結(jié)構(gòu)(比如增加一些變量),但是如果直接更改數(shù)據(jù)塊并下載會(huì)導(dǎo)致其重新初始化。
    的頭像 發(fā)表于 11-10 09:25 ?1476次閱讀
    如何在博途<b class='flag-5'>環(huán)境</b>下載但不重新<b class='flag-5'>初始化</b>數(shù)據(jù)塊呢?

    OP-TEE的內(nèi)核初始化函數(shù)調(diào)用

    generic_boot_init_primary函數(shù)內(nèi)容 generic_boot_init_primary函數(shù)是OP-TEE建立系統(tǒng)運(yùn)行環(huán)境的入口函數(shù),該函數(shù)會(huì)進(jìn)行建立線程運(yùn)行空間、初始化
    的頭像 發(fā)表于 11-02 18:18 ?584次閱讀
    OP-TEE的內(nèi)核<b class='flag-5'>初始化</b>函數(shù)調(diào)用

    ST7789屏幕初始化的步驟

    st7789的屏幕構(gòu)建系統(tǒng)和配置 驅(qū)屏就是初始化 DC轉(zhuǎn)換和cs
    的頭像 發(fā)表于 10-16 09:27 ?4765次閱讀

    SD卡初始化及讀取程序

    電子發(fā)燒友網(wǎng)站提供《SD卡初始化及讀取程序.pdf》資料免費(fèi)下載
    發(fā)表于 10-13 09:50 ?2次下載
    SD卡<b class='flag-5'>初始化</b>及讀取程序