HarmonyOS鸿蒙Next中使用JSVM api运行js陷入死循环,如何结束JSVM

发布于 1周前 作者 wuwangju 来自 鸿蒙OS

HarmonyOS鸿蒙Next中使用JSVM api运行js陷入死循环,如何结束JSVM 开个子线程使用jsvm 创建一个js运行环境,如果js陷入死循环,而OH_JSVM_DestroyEnv是需要在同线程调用的,那就意味着没有一个时机能调用OH_JSVM_DestroyEnv,那怎么结束jsvm呢

3 回复

一般会在NDK侧写一个销毁函数时释放JS环境。

具体可以参考下使用JSVM-API接口创建多个引擎执行JS代码并销毁的Demo:

1、提供创建JSVM运行环境的对外接口并返回对应唯一ID:

static napi_value CreateJsCore(napi_env env1, napi_callback_info info) { 
    OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore START");
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr);
    if (argc < 1) {
        OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore the number of params must be one");
        return nullptr;
    }
    g_napiEnvMap[ENVTAG_NUMBER] = env1;
    g_taskQueueMap[ENVTAG_NUMBER] = deque<Task*>{};
    // 将TS侧传入的回调函数与env对应存储方便后续调用
    napi_ref callFun;
    napi_create_reference(env1, argv[0], 1, &callFun);
    g_callBackMap[ENVTAG_NUMBER] = callFun;
    napi_value coreID = 0;
    {
        std::lock_guard<std::mutex> lock_guard(envMapLock);
        CreateArkJSContext();
        napi_create_uint32(env1, ENVTAG_NUMBER, &coreID);
        ENVTAG_NUMBER++;
    }
    OH_LOG_INFO(LOG_APP, "JSVM CreateJsCore END");
    return coreID;
}

2、对外提供执行JS代码接口,通过coreID在对应的JSVN环境中执行JS代码

static napi_value EvalUateJS(napi_env env, napi_callback_info info) {
    OH_LOG_INFO(LOG_APP, "JSVM EvalUateJS START");
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    uint32_t envId;
    napi_status status = napi_get_value_uint32(env, args[0], &envId);
    if (status != napi_ok) {
        OH_LOG_ERROR(LOG_APP, "EvalUateJS first param should be number");
        return nullptr;
    }
    if (g_envMap.count(envId) == 0 || g_envMap[envId] == nullptr) {
        OH_LOG_ERROR(LOG_APP, "EvalUateJS env is null");
        return nullptr;
    }
    std::string dataStr = napiValueToString(env, args[1]);
    napi_value res = nullptr;
    std::lock_guard<std::mutex> lock_guard(mutexLock);
    {
        // open handle scope
        JSVM_HandleScope handlescope;
        OH_JSVM_OpenHandleScope(*g_envMap[envId], &handlescope);
        // compile js script
        JSVM_Value sourcecodevalue;
        OH_JSVM_CreateStringUtf8(*g_envMap[envId], dataStr.c_str(), dataStr.size(), &sourcecodevalue);
        JSVM_Script script;
        OH_JSVM_CompileScript(*g_envMap[envId], sourcecodevalue, nullptr, 0, true, nullptr, &script);
        // run js script
        JSVM_Value result;
        OH_JSVM_RunScript(*g_envMap[envId], script, &result);
        JSVM_ValueType type;
        OH_JSVM_Typeof(*g_envMap[envId], result, &type);
        OH_LOG_INFO(LOG_APP, "JSVM API TEST type: %{public}d", type);
        // Execute tasks in the current env event queue
        while (!g_taskQueueMap[envId].empty()) {
            auto task = g_taskQueueMap[envId].front();
            g_taskQueueMap[envId].pop_front();
            task->Run();
            delete task;
        }
        if (type == JSVM_STRING) {
            std::string stdResult = fromOHStringValue(*g_envMap[envId], result);
            napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
        } else if (type == JSVM_BOOLEAN) {
            bool ret = false;
            std::string stdResult;
            OH_JSVM_GetValueBool(*g_envMap[envId], result, &ret);
            ret ? stdResult = "true" : stdResult = "false";
            napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
        } else if (type == JSVM_NUMBER) {
            int32_t num;
            OH_JSVM_GetValueInt32(*g_envMap[envId], result, &num);
            std::string stdResult = std::to_string(num);
            napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
        } else if (type == JSVM_OBJECT) {
            JSVM_Value objResult;
            OH_JSVM_JsonStringify(*g_envMap[envId], result, &objResult);
            std::string stdResult = fromOHStringValue(*g_envMap[envId], objResult);
            napi_create_string_utf8(env, stdResult.c_str(), stdResult.length(), &res);
    }
        OH_JSVM_CloseHandleScope(*g_envMap[envId], handlescope);
    }
    OH_LOG_INFO(LOG_APP, "JSVM EvalUateJS END");
    return res;
}

3、对外提供释放JSVM环境接口,通过envId释放对应环境

static napi_value ReleaseJsCore(napi_env env1, napi_callback_info info) {
    OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore START");
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env1, info, &argc, argv, nullptr, nullptr);
    if (argc < 1) {
        OH_LOG_ERROR(LOG_APP, "JSVM ReleaseJsCore the number of params must be one");
        return nullptr;
    }
    uint32_t coreEnvId;
    napi_status status = napi_get_value_uint32(env1, argv[0], &coreEnvId);
    if (status != napi_ok) {
        OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore napi_get_value_uint32 faild");
        return nullptr;
    }
    if (g_envMap.count(coreEnvId) == 0 ) {
        OH_LOG_ERROR(LOG_APP, "JSVM CreateJsCore not has env ");
        return nullptr;
    }
    if (g_envMap[coreEnvId] != nullptr) {
        std::lock_guard<std::mutex> lock_guard(envMapLock);
        OH_JSVM_CloseEnvScope(*g_envMap[coreEnvId], g_envScopeMap[coreEnvId]);
        g_envScopeMap.erase(coreEnvId);
        OH_JSVM_DestroyEnv(*g_envMap[coreEnvId]);
        g_envMap[coreEnvId] = nullptr;
        g_envMap.erase(coreEnvId);
        OH_JSVM_CloseVMScope(*g_vmMap[coreEnvId], g_vmScopeMap[coreEnvId]);
        g_vmScopeMap.erase(coreEnvId);
        OH_JSVM_DestroyVM(*g_vmMap[coreEnvId]);
        g_vmMap[coreEnvId] = nullptr;
        g_vmMap.erase(coreEnvId);
        delete [] g_callBackStructMap[coreEnvId];
        g_callBackStructMap[coreEnvId] = nullptr;
        g_callBackStructMap.erase(coreEnvId);
        napi_delete_reference(env1, g_callBackMap[coreEnvId]);
        g_callBackMap.erase(coreEnvId);
        g_taskQueueMap.erase(coreEnvId);
    }
    OH_LOG_INFO(LOG_APP, "JSVM ReleaseJsCore END");
    return nullptr;
}

cpp目录下导出接口
Index.d.ts

// index.d.ts
export const createJsCore: (fun: Function) => number;
export const releaseJsCore: (a: number) => void;
export const evalUateJS: (a: number, str: string) => string;

使用接口
pages/Index.ets

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';
function MyCallback(a: string, b: string): string {
  console.log("TEST MyCallback run: " + a);
  b = "callback done";
  console.log("TEST MyCallback run: " + b);
  return "callback pass";
}
function MyCallback2(a: string, b: string): string {
  console.log("TEST MyCallback2 start: a =  " + a);
  console.log("TEST MyCallback2 start: b =  " + b);
  return "MyCallback2 pass";
}
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            let sourceCodeStr = `{let a = "hello World";
              consoleinfo(a);
              const mPromise = createPromise();
              mPromise.then((result) => {
              assertEqual(result, 0);
              onJSResultCallback(result, "abc", "v");
              });
              a;
              };`;
            let sourcecodestr1 = `{let a = "second hello";
              consoleinfo(a);
              let b = add(99, 1);
              assertEqual(100, b);
              "assertEqual(add(99, 1), 100);
              createPromise().then((result) => {
              assertEqual(result, 1);
              consoleinfo(onJSResultCallback(result, '999','666'));});
              "a
              };`;
            // 创建首个运行环境,并绑定TS回调
            const coreId = testNapi.createJsCore(MyCallback);
            console.log("TEST coreId: " + coreId);
            // 在首个运行环境中执行JS代码
            console.log("TEST evalUateJS :   " + testNapi.evalUateJS(coreId, sourceCodeStr));
            //创建第二个运行环境,并绑定TS回调
            const coreId1 = testNapi.createJsCore(MyCallback2);
            console.log("TEST coreId: " + coreId1);
            // 在第二个运行环境中执行JS代码
            console.log("TEST evalUateJS :   " + testNapi.evalUateJS(coreId1, sourcecodestr1));
            // 释放首个运行环境
            testNapi.releaseJsCore(coreId);
            // 释放第二个运行环境
            testNapi.releaseJsCore(coreId1);
            hilog.info(0x0000, 'testTag', 'Test NAPI end');
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

更多关于HarmonyOS鸿蒙Next中使用JSVM api运行js陷入死循环,如何结束JSVM的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,如果使用JSVM API运行JS代码时陷入死循环,可以通过以下方式结束JSVM的执行:

  1. 使用JSVM的终止功能:JSVM提供了JSVM::TerminateExecution方法,可以强制终止当前正在执行的JS代码。调用该方法后,JSVM会立即停止执行,并抛出TerminatedExecution异常。

  2. 设置执行超时:在启动JSVM执行JS代码时,可以通过设置超时时间来避免死循环。使用JSVM::SetTimeout方法,指定一个时间限制,超过该时间后JSVM会自动终止执行。

  3. 使用Worker线程:将JS代码放在Worker线程中执行,主线程可以通过Worker::terminate方法强制终止Worker线程,从而结束JS代码的执行。

  4. 监控资源消耗:通过监控JSVM的CPU和内存使用情况,当检测到异常消耗时,可以主动调用终止方法来结束JSVM的执行。

这些方法可以帮助你在鸿蒙Next中有效处理JSVM陷入死循环的情况。

在HarmonyOS鸿蒙Next中,如果使用JSVM API运行JavaScript代码时陷入死循环,可以通过以下方式结束JSVM:

  1. 超时机制:在调用JSVM API时设置超时时间,超过指定时间后自动终止执行。
  2. 手动终止:使用JSVM提供的终止方法,如JSVM::TerminateExecution(),强制结束当前执行的JavaScript代码。
  3. 资源监控:监控CPU和内存使用情况,发现异常时及时终止JSVM。

确保在开发过程中合理使用这些机制,避免死循环对系统性能的影响。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!