Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

使用QuickJS标准库

Github代码链接

使用QuickJS标准库

QuickJS有自己的标准库(输入输出,文件操作,json操作等),详见QuickJS-NG文档。但是要使用的话需要调用额外函数进行初始化。

HelloWorld章节已经看到了如何注册console.log和其他全局变量/函数了。其他的函数则需要通过js_init_module_xxx进行初始化:

js_init_module_os(ctx, "os");
js_init_module_std(ctx, "std");
js_init_module_bjson(ctx, "json");

第二个参数是库注册的名称。

JS代码加载库

有至少三种方式:

使用模块模式执行代码

如果想要在JS代码中使用

import * as std from 'std'

这类代码,在执行代码时必须将其视为模块执行:

JSValue result = JS_Eval(ctx, content.c_str(), content.size(), nullptr, 
                         // use this flag!
                         JS_EVAL_TYPE_MODULE);

否则会说没有import语法。

作为模块执行的话有一个很严重的缺点:如果出现某些语法错误/运行时错误,QuickJS会直接静默而非抛出异常。这意味着调试困难。一般如果模块找不到的话他会正常报错。但是在你使用模块内部的对象(比如对一个不存在的类进行new),QuickJS则会abort,并且不会抛出异常(检查JS_Eval的返回值不会是异常)

使用异步加载方式加载

这种方式可以不以模块方式加载:

import('std').then(module => {
    module.puts("I am std module in non-module mode\n");
}).catch(err => {
    print("Error loading module:", err);
});

但这是一段异步代码。我们需要在执行完之后使用js_std_loopjs_std_await等待异步执行完毕:

JSValue result = JS_Eval(ctx, content.c_str(), content.size(), nullptr, JS_EVAL_FLAG_GLOBAL);
js_std_loop(ctx);

js_std_loop会对整个JSContext中需要等待的脚本做等待。只指定某个脚本等待的话需调用js_std_await

预加载模块,然后执行

我们也可以走两步:

  1. 先通过模块模式import需要的模块入JSContext
  2. 执行我们自己的代码。这样可以直接使用已经导入的模块

这里首先以模块模式执行:

std::cout << "execute in pre-module mode" << std::endl;
const char* module_preload_code = R"(
    import * as std from 'std';
    globalThis.std = std;
)";
auto value =
    JS_Eval(ctx, module_preload_code, strlen(module_preload_code), nullptr, JS_EVAL_TYPE_MODULE);

注意这里需要将模块放入globalThis中。

然后执行我们自己的代码:

std.puts("I am std module when preload module\n") // call function in std module
JSValue result = JS_Eval(ctx, content.c_str(), content.size(), nullptr, JS_EVAL_FLAG_GLOBAL);