qjs/README_zh-cn.md

6.5 KiB
Raw Permalink Blame History

quickjs-go

English | 简体中文

源自 https://github.com/buke/quickjs-go, 修复了函数回调时的性能问题

Test codecov Go Report Card GoDoc FOSSA Status

Go 语言的QuickJS绑定库快速、小型、可嵌入的ES2020 JavaScript解释器。

功能

  • 执行javascript脚本
  • 编译javascript脚本到字节码并执行字节码
  • 在 Go 中操作 JavaScript 值和对象
  • 绑定 Go 函数到 JavaScript 同步函数和异步函数
  • 简单的异常抛出和捕获

指南

  1. 在使用完毕后,请记得关闭 quickjs.Runtimequickjs.Context
  2. 请记得关闭由 Eval()EvalFile() 返回的 quickjs.Value。其他值不需要关闭,因为它们会被垃圾回收。
  3. 如果你使用了promise 或 async function请使用 ExecuteAllPendingJobs 等待所有的promise/job结果。
  4. You may access the stacktrace of an error returned by Eval() or EvalFile() by casting it to a *quickjs.Error.
  5. 如果Eval()EvalFile()返回了错误,可强制转换为*quickjs.Error以读取错误的堆栈信息。
  6. 如果你想在函数中返回参数,请在函数中复制参数。

用法

import "apigo.cloud/git/apigo/qjs"

执行javascript脚本

package main

import (
	"fmt"
    
	"apigo.cloud/git/apigo/qjs"
)

func main() {
    // Create a new runtime
    rt := quickjs.NewRuntime()
    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())
}

读取/设置 JavaScript 对象

package main

import (
	"fmt"
    
	"apigo.cloud/git/apigo/qjs"
)

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 "apigo.cloud/git/apigo/qjs"

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
	rt.ExecuteAllPendingJobs()

    //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"
    
	"apigo.cloud/git/apigo/qjs"
)

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())
}

Bytecode编译和执行


package main

import (
	"fmt"
    
	"apigo.cloud/git/apigo/qjs"
)

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())
}

设置内存、栈、GC等等

package main

import (
	"fmt"
    
	"apigo.cloud/git/apigo/qjs"
)

func main() {
    // Create a new runtime
    rt := quickjs.NewRuntime()
    defer rt.Close()

    // set runtime options
    rt.SetMemoryLimit(256 * 1024) //256KB
    rt.SetMaxStackSize(65534)

    // Create a new context
    ctx := rt.NewContext()
    defer ctx.Close()

    result, err := ctx.Eval(`var array = []; while (true) { array.push(null) }`)
    defer result.Free()
}

文档

Go 语言文档和示例: https://pkg.go.dev/github.com/buke/quickjs-go

协议

MIT

FOSSA Status

相关项目