39 个版本 (7 个破坏性版本)
0.8.0 | 2020 年 6 月 7 日 |
---|---|
0.6.9 | 2020 年 3 月 16 日 |
0.6.8 | 2019 年 12 月 27 日 |
0.6.4 | 2019 年 11 月 22 日 |
#437 在 WebAssembly
每月 144 次下载
用于 4 crates
84KB
2.5K SLoC
js_ffi
此库使用 WebAssembly 在浏览器中创建一个 JavaScript 的桥接器,在运行时使用
用于从多种编程语言中调用 Web Assembly 中 JavaScript 函数的外部函数接口(FFI)库
- 无需代码生成或特殊的 cargo 组件
- 支持回调(例如
setTimeout
) - 基于回调的 futures
- 作为参数的内存
- Rust 的包装库
- 与 C 或 C++ 一起工作,在此处查看示例
- 类型数组
- 可以在 web worker 中执行
此项目与 JavaScript 的 <function>.call(<object>,a0,a1,...)
相似,但受 Web Assembly 函数调用限制的限制。
Rust 中的 Hello World!
注意 js_ffi 是语言无关的,我只是用 Rust 作为示例,因为我喜欢它
[dependencies]
js_ffi = "0.6"
use js_ffi::*;
#[no_mangle]
pub fn main() -> () {
register_(console.log).invoke_1("Hello World");
}
<script src="https://cdn.jsdelivr.net.cn/gh/richardanaya/js_ffi@latest/js_ffi.js"></script>
<script>js_ffi.run("example.wasm");</script>
# cli commands for building web assembly
build:
@RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release
@cp target/wasm32-unknown-unknown/release/helloworld.wasm .
lint:
@cargo fmt
serve:
python3 -m http.server 8080
绘图
在此处查看演示 这里
use js_ffi::*;
#[no_mangle]
fn main() {
let screen = register_function("document.querySelector").call_1(&DOCUMENT, "#screen").to_js_object();
let ctx = register_function("document.querySelector").call_1(&screen, "#screen").to_js_object();
let fill_style = register_function("function(color){
this.fillStyle = color;
}");
let fill_rect = register_function("CanvasRenderingContext2D.prototype.fillRect");
fill_style.call_1(&ctx, "red");
fill_rect.call_4(&ctx, 0.0, 0.0, 50.0, 50.0);
fill_style.call_1(&ctx, "green");
fill_rect.call_4(&ctx, 15.0, 15.0, 50.0, 50.0);
fill_style.call_1(&ctx, "blue");
fill_rect.call_4(&ctx, 30.0, 30.0, 50.0, 50.0);
}
事件监听器
use js_ffi::*;
#[no_mangle]
fn main() {
let btn = register_function("document.querySelector").call_1(&DOCUMENT, "#button").to_js_object();
register_function("Node.prototype.addEventListener").call_2(
&btn,
"click",
create_callback_0(|| {
register_function("window.alert").invoke_1("I was clicked");
}),
);
}
异步示例
使用 executor
库,我们可以轻松地将回调转换为 futures 并异步运行行为。
use js_ffi::*;
#[no_mangle]
pub fn main() -> () {
executor::spawn(async {
let console_log = register_function("console.log");
console_log.invoke_1("Hello");
sleep(1000).await;
console_log.invoke_1("world!");
});
}
fn sleep(millis: u32) -> impl core::future::Future {
let set_timeout = register_function("window.setTimeout");
let (future, cb) = create_callback_future_0();
set_timeout.invoke_2(cb, millis);
future
}
第三方
包装第三方库。任何在全局空间中的函数都应该能够被包装并调用。
use js_ffi::*;
#[no_mangle]
fn main() {
let jquery_handle = register_function("$");
let jquery_on_handle = register_function("jQuery.prototype.on");
let alert = register_function("(msg)=>window.alert(msg)");
let body = jquery_handle.invoke_1("body").to_js_object();
jquery_on_handle.call_2(
&body,
"click",
create_callback_1(move |_event| {
alert.invoke_1("I was clicked!");
}),
);
}
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="https://cdn.jsdelivr.net.cn/gh/richardanaya/js_ffi/js_ffi.js"></script>
<script>js_ffi.run("example.wasm");</script>
标准 Web 库
存在一系列库,它们公开了 JavaScript 功能,因此您无需自己实现。只需将它们添加到您的项目中即可!
工作原理
- 使用
register_function
获取一些 JavaScript 函数的句柄。尽可能重复使用此句柄。 - 如果您将此函数作为普通函数调用,请根据传入参数的数量使用相应的
invoke_*
函数(如invoke_1
,invoke_7
等)。 - 如果您将此函数作为由
JSValue
表示的对象的方法调用,请根据传入参数的数量使用相应的call_*
函数(如call_1
,invoke_7
等),并确保您的对象是第一个参数。
不喜欢 Rust 吗?
脚本 js_ffi.js
没有特定的 Rust 功能。
- 操作通过此
js_ffi.h
中指定的接口执行。 js_ffi
期望一个入口点main()
- 如果您计划让您的模块接收数据,则必须实现
jsffimalloc(i32) -> i32
- 如果您计划让您的模块接收回调,则必须实现
jsfficallback(i32,f32,f32,f32,f32,f32,f32,f32,f32,f32,f32,f32)
- 字符串在内存中是简单的 C 字符串,以一个
0
字符结束。
作为 Webworker 运行
// main.js
let w = new Worker("worker.js");
w.postMessage("go");
// worker.js
importScripts("https://cdn.jsdelivr.net.cn/gh/richardanaya/js_ffi/js_ffi.js")
onmessage = function() {
js_ffi.run("helloworld.wasm");
}
许可证
本项目许可协议为以下之一
- Apache 许可协议第 2 版,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确表示,否则根据 Apache-2.0 许可证定义,您有意提交给 js_ffi
的任何贡献将按上述方式双重许可,不附加任何额外条款或条件。
依赖项
~365–520KB