Sciter 6.0.1.0 重磅更新:sciter.js 中直接操作原生 C 模块支持正式登场

介绍

近日,Sciter 团队发布了一项震撼演示------将 three.js 经典的 webgl buffergeometry 线条绘制案例移植到 C 模块环境中。这个包含 500 个 3D 粒子(总计算量达 500×500/2=125,000 次/帧)的粒子系统,在动画过程中需要实时计算粒子间距离:

左侧为 Sciter 运行效果,右侧为 MS Edge,均保持 60FPS。 要知道这种平方级复杂度计算(O(N²))会导致 V8引擎 JIT 优化失效,并且高频函数容易调用引发 GC 停顿。

然后在最新发布的 Sciter 6.0.1.0 中,这一革命性功能------ CModules( C 语言模块)就正式落地!这意味着开发者现在可以用纯 C 语言编写高性能模块,并与 JavaScript 无缝交互。

象我们如果做游戏开发,需要在物理引擎/3D 计算加速一些高性能的计算,或在密码学需要高性能加密算法实现。都能直接在 sciter.js 本身来实现了。

CModules 核心特性速览

通过集成轻量级编译器 TinyCC(支持 ANSI C / C99 / GNU 扩展 ),Sciter 实现了三大创新设计:

  1. 模块化编译

    • 独创的 #import "file.c" 语法,支持多文件联合编译(类似C项目的多编译单元管理)
    • 示例代码见官方 SDK 的 /sdk/samples.c 目录
  2. 双向交互通道

    • 使用 export 关键字标记需要暴露给JS的C函数
    • 引入 jsvalue 数据类型(直接操作JS对象的神器)
    • 支持整型家族(int8/16/32/64)、浮点类型、指针以及JS对象引用
  3. 安全沙箱机制

    • 默认关闭模式需通过 ALLOW_CMODULES 显式开启
    • 编译时需在 premake5.lua 添加 --CMODULES 编译参数
js 复制代码
 SciterSetOption(NULL, SCITER_SET_SCRIPT_RUNTIME_FEATURES,
                         ALLOW_FILE_IO |
                         ALLOW_SOCKET_IO |
                         ALLOW_EVAL |
                         ALLOW_SYSINFO | 
                         ALLOW_CMODULES // <<<<<<<<<<<<<<<
                 );

这个带来的优势如下

  1. 内存直通技术:C 模块直接操作 WebGL 缓冲区内存,消除 JS 与 Native 的数据拷贝
  2. SIMD指令优化:TinyCC 编译器自动生成 SSE/AVX 向量化指令
  3. 零GC压力:堆外内存管理避免 JavaScript 引擎的垃圾回收抖动

从C到JS的无缝衔接

c 复制代码
// 示例:高性能数学计算模块
export double calculateHypotenuse(double a, double b) {
    return sqrt(a*a + b*b); // 毕达哥拉斯定理的C语言实现
}

// 示例:处理复杂JS对象
export jsvalue processUserData(jsvalue input) {
    // 使用Sciter内置API操作JS对象
    if(is_string(input)) {
        const char* str = get_string(input);
        //... 复杂字符串处理
    }
    return create_object(); // 返回新JS对象
}

使用

启用方法

lua 复制代码
-- premake5.lua 配置示例
project "YourApp"
    add_cmodules("--CMODULES") -- 魔法开关在此

我们在运行时初始化,需要在头文件中加上如下内容。

c 复制代码
// 运行时初始化(安全第一!)
SciterSetOption(NULL, 
               SCITER_SET_SCRIPT_RUNTIME_FEATURES,
               ALLOW_FILE_IO |    // 文件操作
               ALLOW_SOCKET_IO |   // 网络通信
               ALLOW_EVAL |        // 动态执行
               ALLOW_SYSINFO |    // 系统信息
               ALLOW_CMODULES     // C模块开关 ←重点!
              );

【技术深潜】与传统方案相比,Sciter的C模块实现了三大突破:

  1. 编译速度提升:TinyCC 的即时编译特性比传统编译器快 10 倍以上
  2. 内存安全:独创的 jsvalue 封装层避免野指针问题
  3. 跨平台一致性:Windows/macOS/Linux 三端统一 ABI 接口

目前该功能已在 GitHub 的 Sciter.GLX 分支开放测试,期待开发者们用 C 语言打破性能边界!其中jsbridge.h 头文件扮演着连接 JavaScript 与 C 世界的桥梁角色

转换速查

函数类别 明星函数 应用场景
基础类型转换 int32_to_jsvalue() 处理标量参数/返回值
指针操作 float_to_jsvalue() 传递预先分配的缓冲区
高级构造 _jsvalue_new() 构建复杂JS对象/数组
数据提取 _jsvalue_fetch() 解析来自JS的结构化数据
类型探测 _jsvalue_type() 运行时类型安全检查
内存管理 _jsvalue_addref() 长生命周期对象管理

常见问题需要注意:

  • 在非主线程操作jsvalue(Sciter JS单线程特性)
  • 忽略jsvalue_type检查导致类型转换崩溃
  • 循环引用造成的内存泄漏(C↔JS对象互引用)

最新调试工具链已加入JSVALUE_DEBUG_TRACING编译选项,可实时追踪jsvalue生命周期。

实例 demo

如下是作者 Andrew 在这使用了一个 c 模块和一个 js 实现相同功能的对比。 这里的 C 模块的功能类似于 JS 模块,但其 C 源代码会被实时编译为原生代码。因此这些是原生模块,无需额外安装C编译器,因为 Sciter 内置了 tinycc 引擎。

js 复制代码
<html>
    <head>
        <script|module>

import * as cmod from "./cmod.c"; // C module
import * as jsmod from "./jsmod.js"; // JS module

const floats = new Float32Array(3000);
for(let i = 0; i < floats.length; ++i)
  floats[i] = Math.random();

function time(f) {
  let a = new Date().getTime();
  f();
  let b = new Date().getTime();
  return b - a;
}

let d1, d2;

// JS version
let t1 = time(() => d1 = jsmod.closestDistance(floats));
// native C version
let t2 = time(() => d2 = cmod.closestDistance(floats));

document.body.append(<ul>
    <li>JS res=<var>{printf("%f",d1)}</var> exectime=<var>{t1}ms</var></li>
    <li>C res=<var>{printf("%f",d2)}</var> exectime=<var>{t2}ms</var></li>
</ul>);
        </script>
    </head>
    <body>
    </body>
</html>

以下是那个cmod.c文件的源代码:

c++ 复制代码
#include <math.h>
#include <jsbridge.h>

export float closestDistance(floats dots) {
  float m = 3.0;
  for( int i = 0; i < dots.length; i += 3 ) {
    for( int j = 0; j < dots.length; j += 3 ) {
      if( i == j) continue;
      float x = dots.data[i] - dots.data[j];
      float y = dots.data[i+1] - dots.data[j+1];
      float z = dots.data[i+2] - dots.data[j+2];
      float d = sqrtf(x*x + y*y + z*z);
      if( d < m ) m = d;
    }
  }
  return m;
}

为了完整性,jsmod.js 也实现了相同的功能并对外暴露:

js 复制代码
export function closestDistance(dots) {
  let m = 3.0;
  for( let i = 0; i < dots.length; i += 3 ) {
    for( let j = 0; j < dots.length; j += 3 ) {
      if( i == j) continue;
      let x = dots[i] - dots[j];
      let y = dots[i+1] - dots[j+1];
      let z = dots[i+2] - dots[j+2];
      let d = Math.sqrt(x*x + y*y + z*z);
      if( d < m ) m = d;
    }
  }
  return m;
}

sciter.js 大神的对比

相关推荐
海晨忆1 小时前
【Vue】v-if和v-show的区别
前端·javascript·vue.js·v-show·v-if
JiangJiang1 小时前
🚀 Vue人看React useRef:它不只是替代 ref
javascript·react.js·面试
1024小神1 小时前
在GitHub action中使用添加项目中配置文件的值为环境变量
前端·javascript
龙骑utr2 小时前
qiankun微应用动态设置静态资源访问路径
javascript
Jasmin Tin Wei2 小时前
css易混淆的知识点
开发语言·javascript·ecmascript
wsz77772 小时前
js封装系列(一)
javascript
卫崽2 小时前
JavaScript 中的 ?? 与 || 运算符详解
javascript·面试
1024小神2 小时前
GitHub action中的 jq 是什么? 常用方法有哪些
前端·javascript
逆袭的小黄鸭2 小时前
JavaScript 开发必备规范:命名、语法与代码结构指南
前端·javascript·面试
不简说2 小时前
sv-print可视化打印组件不完全指南⑤
前端·javascript·前端框架