Skip to content

buke/quickjs-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

quickjs-go

English | 简体中文

Test codecov Go Report Card GoDoc FOSSA Status

Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

Features

  • Evaluate script
  • Compile script into bytecode and Eval from bytecode
  • Operate JavaScript values and objects in Go
  • Bind Go function to JavaScript async/sync function
  • Simple exception throwing and catching

Guidelines

  1. Free quickjs.Runtime and quickjs.Context once you are done using them.
  2. Free quickjs.Value's returned by Eval() and EvalFile(). All other values do not need to be freed, as they get garbage-collected.
  3. Use ExecuteAllPendingJobs wait for promise/job result after you using promise/job
  4. You may access the stacktrace of an error returned by Eval() or EvalFile() by casting it to a *quickjs.Error.
  5. Make new copies of arguments should you want to return them in functions you created.

Usage

import "github.com/buke/quickjs-go"

Run a script

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() ret, err := ctx.Eval("'Hello ' + 'QuickJS!'") if err != nil { println(err.Error()) } fmt.Println(ret.String()) }

Get/Set Javascript Object

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

Bind Go Funtion to Javascript async/sync function

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 rt.ExecuteAllPendingJobs() //get promise result asyncRet, _ := ctx.Eval("ret") defer asyncRet.Free() fmt.Println(asyncRet.String()) // Output: // Hello Javascript! // Hello Golang! // Hello Async Function! }

Error Handling

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

Bytecode Compiler

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

Runtime Options: memory, stack, GC, ...

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

Documentation

Go Reference & more examples: https://pkg.go.dev/github.com/buke/quickjs-go

License

MIT

FOSSA Status

Related Projects

About

Go bindings to QuickJS

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 6