前段时间研究了 JerryScript 库,趁着还没有完全遗忘之前,做个记录,以作备忘。

JerryScript 是一个轻量级的 JavaScript 引擎,资源占用极少,它可以运行在资源受限制的设备上,如:

  • 只有几 KB RAM 能运行引擎的设备(<64 KB RAM)
  • 只能为代码引擎提供有限 ROM 空间的设备(<200 KB ROM)

JerryScript 使用 C 语言开发,跨平台,而且在各个平台上都可以很方便的进行编译。

为什么没有选择 QuickJS?

说起轻量级的 JavaScript 引擎,很多人都会想到 QuickJS。的确,我一开始也选择了 QuickJS,但一番研究之后,发现 QuickJS 在 Windows 环境下编译实在是不太友好,不仅需要安装 Mingw64,而且修改编译选项也不方便。可能是我能力的问题吧,我还未找到将 QuickJS 编译成 MT 运行库的静态库的方法。

一个库在编译方面都不够友好,那就没必要委屈自己了,毕竟还有其他的选择。

反观 JerryScript,使用 CMake 进行构建,不需要进行任何修改。

快速上手

JerryScript 的接口比较简洁, 而且官方已经提供了丰富的示例,示例地址如下:

https://jerryscript.net/api-example/

下面是一个简单的示例,演示了如何暴露 C++ 的函数给 JS 进行调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include "jerryscript.h"

// C++ 函数,用于暴露给 JS
static jerry_value_t print_handler(
const jerry_call_info_t* call_info_p,
const jerry_value_t arguments[],
const jerry_length_t argument_count) {
// 没有参数,只打印一个字符串
printf("Print handler was called\n");

// 返回 undefined 给JS引擎
return jerry_undefined();
}

int main(void) {
const jerry_char_t script[] = "print ();";
const jerry_length_t script_size = sizeof(script) - 1;

// 初始化引擎
jerry_init(JERRY_INIT_EMPTY);

// 添加 print 方法到 JavaScript 的全局对象上
// 在JS 中调用 print 方法时,会调用到 C++ print_handler 方法
{
jerry_value_t global_object = jerry_current_realm();
jerry_value_t property_name_print = jerry_string_sz("print");
jerry_value_t property_value_func = jerry_function_external(print_handler);
jerry_value_t set_result = jerry_object_set(global_object, property_name_print, property_value_func);

// 检查是否有错误发生
if (jerry_value_is_exception(set_result)) {
printf("Failed to add the 'print' property\n");
}

jerry_value_free(set_result);
jerry_value_free(property_value_func);
jerry_value_free(property_name_print);
jerry_value_free(global_object);
}

jerry_value_t parsed_code = jerry_parse(script, script_size, NULL);
if (!jerry_value_is_exception(parsed_code))
{
// 执行 JS 代码
jerry_value_t ret_value = jerry_run(parsed_code);

// 释放返回值
jerry_value_free(ret_value);
}

jerry_value_free(parsed_code);
jerry_cleanup();

return 0;
}