Go调用JS脚本
Goja
项目地址:goja
基本使用
func main(){
vm := goja.New()
val, err := vm.RunString(`
2+2
`)
if err != nil {
log.Fatalln(err)
}
if v, ok := val.Export().(int64); ok {
fmt.Println(v)
}
}
传值到 js 中
func main(){
vm := goja.New()
vm.Set("println", func(args ...interface{}) {
fmt.Println(args)
})
_, err := vm.RunString(`
println("Hello world")
`)
if err != nil {
log.Fatalln(err)
}
}
还可以使用 vm.ToValue()
func main(){
vm := goja.New()
vm.Set("println", func(args ...interface{}) {
fmt.Println(args)
})
_, err := vm.RunString(`
function log(param){
println(param)
}
`)
if err != nil {
log.Fatalln(err)
}
// 获取 js 中的函数。
callbal, ok := goja.AssertFunction(vm.Get("log"))
if ok {
callbal(goja.Undefined(), vm.ToValue(map[string]interface{}{
"name": "xiaoming",
"age": 18,
}))
}
}
从 js 中导出函数
func main(){
vm := goja.New()
_, err := vm.RunString(`
function f(param){
return +param+2
}
`)
if err != nil {
log.Fatalln(err)
}
var f func(val int) int
err = vm.ExportTo(vm.Get("f"), &f) // 第二个参数必须是指针
if err != nil {
log.Fatalln(err)
}
fmt.Println(f(40))
}
匹配结构体字段和方法名称
有两个方法:TagFieldNameMapper 和UncapFieldNameMapper
type tagtest struct {
Test string `json:"test"`
}
func (tagtest) Method(s string) string {
return s
}
func tag() {
vm := goja.New()
t := tagtest{
Test: "passed",
}
vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
vm.Set("t", t)
val, err := vm.RunString(`
t.test + " and " + t.method("passed too")
`)
if err != nil {
log.Fatalln(err)
}
fmt.Println(val.Export())
}
type uncaptest struct {
Test string
}
func (uncaptest) Method(s string) string {
return s
}
func uncap(){
vm := goja.New()
u := uncaptest{
Test: "passed",
}
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
vm.Set("u", u)
val, err := vm.RunString(`
u.test + " and " + u.method("passed too")
`)
if err != nil {
log.Fatalln(err)
}
fmt.Println(val.Export())
}
异常
// go 中捕获 js 异常
func catch() {
vm := goja.New()
_, err := vm.RunString(`
throw("Test");
`)
if jserr, ok := err.(*goja.Exception); ok {
if jserr.Value().Export() != "Test" {
panic("wrong value")
}
} else {
panic("wrong type")
}
}
// js 中捕获 go panic
func catch2() {
vm := goja.New()
test := func() {
panic(vm.ToValue("Error"))
}
vm.Set("test", test)
_, err := vm.RunString(`
try{
test()
}catch(e){
if (e !== "Error") {
throw e;
}
}
`)
if err != nil {
panic(err)
}
}
中断
func TestInterrupt(t *testing.T) {
const SCRIPT = `
var i = 0;
for (;;) {
i++;
}
`
vm := goja.New()
time.AfterFunc(200*time.Millisecond, func() {
vm.Interrupt("halt")
})
_, err := vm.RunString(SCRIPT)
if err == nil {
t.Fatal("Err is nil")
}
// err is of type *InterruptError and its Value() method returns whatever has been passed to vm.Interrupt()
}