English | 简体中文
Go 语言的 QuickJS 绑定库:快速、小型、可嵌入的 ES2020 JavaScript 解释器。
使用预编译的 quickjs 静态库,支持以下平台:
平台 | 架构 | 静态库 |
---|---|---|
Linux | x64 | libquickjs.a |
Linux | arm64 | libquickjs.a |
Windows | x64 | libquickjs.a |
Windows | x86 | libquickjs.a |
MacOS | x64 | libquickjs.a |
MacOS | arm64 | libquickjs.a |
* windows 构建步骤请参考:#151 (comment)
quickjs-go | QuickJS |
---|---|
v0.1.x | v2021-03-27 |
v0.2.x | v2023-12-09 |
v0.3.x | v2024-01-13 |
v0.4.x | v2024-02-14 |
- 执行 javascript 脚本
- 编译 javascript 脚本到字节码并执行字节码
- 在 Go 中操作 JavaScript 值和对象
- 绑定 Go 函数到 JavaScript 同步函数和异步函数
- 简单的异常抛出和捕获
- 在使用完毕后,请记得关闭
quickjs.Runtime
和quickjs.Context
。 - 请记得关闭由
Eval()
和EvalFile()
返回的quickjs.Value
。其他值不需要关闭,因为它们会被垃圾回收。 - 如果你使用了 promise 或 async function,请使用
ctx.Loop()
等待所有的 promise/job 结果。 - 如果
Eval()
或EvalFile()
返回了错误,可强制转换为*quickjs.Error
以读取错误的堆栈信息。 - 如果你想在函数中返回参数,请在函数中复制参数。
import "github.com/buke/quickjs-go"
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// Create a new runtime
rt := quickjs.NewRuntime(
quickjs.WithExecuteTimeout(30),
quickjs.WithMemoryLimit(128*1024),
quickjs.WithGCThreshold(256*1024),
quickjs.WithMaxStackSize(65534),
quickjs.WithCanBlock(true),
)
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
ret, err := ctx.Eval("'Hello ' + 'QuickJS!'")
if err != nil {
println(err.Error())
}
fmt.Println(ret.String())
}
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// Create a new runtime
rt := quickjs.NewRuntime()
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
test := ctx.Object()
test.Set("A", ctx.String("String A"))
test.Set("B", ctx.String("String B"))
test.Set("C", ctx.String("String C"))
ctx.Globals().Set("test", test)
ret, _ := ctx.Eval(`Object.keys(test).map(key => test[key]).join(" ")`)
defer ret.Free()
fmt.Println(ret.String())
}
package main
import "github.com/buke/quickjs-go"
func main() {
// Create a new runtime
rt := quickjs.NewRuntime()
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
// Create a new object
test := ctx.Object()
defer test.Free()
// bind properties to the object
test.Set("A", test.Context().String("String A"))
test.Set("B", ctx.Int32(0))
test.Set("C", ctx.Bool(false))
// bind go function to js object
test.Set("hello", ctx.Function(func(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
return ctx.String("Hello " + args[0].String())
}))
// bind "test" object to global object
ctx.Globals().Set("test", test)
// call js function by js
js_ret, _ := ctx.Eval(`test.hello("Javascript!")`)
fmt.Println(js_ret.String())
// call js function by go
go_ret := ctx.Globals().Get("test").Call("hello", ctx.String("Golang!"))
fmt.Println(go_ret.String())
//bind go function to Javascript async function
ctx.Globals().Set("testAsync", ctx.AsyncFunction(func(ctx *quickjs.Context, this quickjs.Value, promise quickjs.Value, args []quickjs.Value) {
promise.Call("resolve", ctx.String("Hello Async Function!"))
}))
ret, _ := ctx.Eval(`
var ret;
testAsync().then(v => ret = v)
`)
defer ret.Free()
// wait for promise resolve
ctx.Loop()
//get promise result
asyncRet, _ := ctx.Eval("ret")
defer asyncRet.Free()
fmt.Println(asyncRet.String())
// Output:
// Hello Javascript!
// Hello Golang!
// Hello Async Function!
}
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// Create a new runtime
rt := quickjs.NewRuntime()
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
ctx.Globals().SetFunction("A", func(ctx *Context, this Value, args []Value) Value {
// raise error
return ctx.ThrowError(expected)
})
_, actual := ctx.Eval("A()")
fmt.Println(actual.Error())
}
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// Create a new runtime
rt := quickjs.NewRuntime()
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
jsStr := `
function fib(n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
fib(10)
`
// Compile the script to bytecode
buf, _ := ctx.Compile(jsStr)
// Create a new runtime
rt2 := quickjs.NewRuntime()
defer rt2.Close()
// Create a new context
ctx2 := rt2.NewContext()
defer ctx2.Close()
//Eval bytecode
result, _ := ctx2.EvalBytecode(buf)
fmt.Println(result.Int32())
}
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// Create a new runtime
rt := quickjs.NewRuntime()
defer rt.Close()
// set runtime options
rt.SetExecuteTimeout(30) // Set execute timeout to 30 seconds
rt.SetMemoryLimit(256 * 1024) // Set memory limit to 256KB
rt.SetMaxStackSize(65534) // Set max stack size to 65534
rt.SetGCThreshold(256 * 1024) // Set GC threshold to 256KB
rt.SetCanBlock(true) // Set can block to true
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
result, err := ctx.Eval(`var array = []; while (true) { array.push(null) }`)
defer result.Free()
}
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
func main() {
// enable module import
rt := quickjs.NewRuntime(quickjs.WithModuleImport(true))
defer rt.Close()
ctx := rt.NewContext()
defer ctx.Close()
// eval module
r1, err := ctx.EvalFile("./test/hello_module.js")
defer r1.Free()
require.NoError(t, err)
require.EqualValues(t, 55, ctx.Globals().Get("result").Int32())
// load module
r2, err := ctx.LoadModuleFile("./test/fib_module.js", "fib_foo")
defer r2.Free()
require.NoError(t, err)
// call module
r3, err := ctx.Eval(`
import {fib} from 'fib_foo';
globalThis.result = fib(9);
`)
defer r3.Free()
require.NoError(t, err)
require.EqualValues(t, 34, ctx.Globals().Get("result").Int32())
}
Go 语言文档和示例: https://pkg.go.dev/github.com/buke/quickjs-go