Duktape JS多上下文持独立全局时如何实现跨脚本共享单例对象
实现方案(基于Duktape嵌入环境)
你当前的需求本质是在多个隔离的JS全局上下文之间共享一个单例对象,Duktape原生提供了堆级别的存储能力,可以非常轻量的实现该需求,以下是两种生产环境常用的实现方式:
方案1:独立全局环境预注入共享对象(最推荐,无副作用)
这是最轻量、无原型污染的实现方式,只需要在C层做两处修改即可:
步骤1:初始化阶段创建全局共享的ueber单例
在Duktape上下文初始化完成后、加载任何业务脚本之前,执行一次以下代码,把ueber对象存入堆存储(heap stash,Duktape堆全局持有,不会被GC,所有上下文都可访问):
// 初始化阶段仅执行1次 duk_push_object(js_context_duk); // 创建空的ueber共享对象 // 如果需要给ueber预置内置方法/属性,可以在这里补充定义 // duk_push_c_function(js_context_duk, your_c_func, 0); // duk_put_prop_string(js_context_duk, -2, "builtinMethod"); duk_put_heap_stash(js_context_duk, "shared_ueber"); // 存入堆存储永久持有
步骤2:每个新脚本初始化时注入ueber到其独立全局作用域
你当前每个脚本有独立全局作用域,应该是每个脚本加载前都会创建新的全局对象,在创建完新的全局对象之后、执行业务脚本之前,执行以下代码注入共享对象:
// 每个独立脚本初始化时执行 duk_get_heap_stash(js_context_duk, "shared_ueber"); duk_put_global_string(js_context_duk, "ueber");
完成以上两步后,所有脚本里访问的ueber都是同一个对象的引用,修改/读取属性都是全局共享的,完全符合你给出的使用示例要求。
方案2:原型链挂载共享对象
如果你不想每次初始化脚本都手动注入,可以把ueber挂载到所有对象的公共原型链上,缺点是会轻微污染原型,不需要额外的注入操作:
// 初始化阶段执行一次 duk_push_object(js_context_duk); // 创建ueber对象 duk_get_global_string(js_context_duk, "Object"); duk_get_prop_string(js_context_duk, -1, "prototype"); duk_put_prop_string(js_context_duk, -2, "ueber"); duk_pop_2(js_context_duk);
效果验证
按照上述方案实现后,你的示例代码可以正常运行:
- 脚本2执行
ueber.a=1后,脚本1内读取ueber.a即可得到正确的值,所有脚本对ueber的属性修改全局生效 - 各脚本的其他全局变量仍然是隔离的,不会互相污染
内容的提问来源于stack exchange,提问作者Heiner
相关产品推荐
相关产品推荐

