首页 体育 教育 财经 社会 娱乐 军事 国内 科技 互联网 房产 国际 女人 汽车 游戏

用Golang运行JavaScript

2019-12-16

Hello world

照着库房的Readme,来一个:

package main
import  {
 vm := js.New // 创立engine实例
 r, _ := vm.RunString // 履行javascript代码
 v, _ : = r.Export. // 将履行的成果转化为Golang对应的类型
 fmt.Println
}仿制代码

这个比方展现了最根本的才干,给定一段Javascript的代码文本,它能履行得到一个成果,并且能得到履行成果的宿主言语的表明方式。

Javascript和Golang之间的交互分红两个方面:Golang向Javascript引擎中注入一些上下文,例如注册一些大局函数供Javascript运用,创立一个目标等;Golang从Javascript引擎中读取一些上下文,例如一个核算进程的核算成果。先看第一类。

常用的手法是,经过Runtime类型供给的Set办法在大局注册一个变量,例如

...
rts := js.New
rts.Set
rts.RunString // 4
...仿制代码
此处Set的办法签名是 func Set ,关于根本类型,不需求额定的包装,就能够主动转化,可是当需求传递一个杂乱目标时,需求用 NewObject 包装一下:

照着库房的Readme,来一个:

package main
import  {
 vm := js.New // 创立engine实例
 r, _ := vm.RunString // 履行javascript代码
 v, _ : = r.Export. // 将履行的成果转化为Golang对应的类型
 fmt.Println
}仿制代码

这个比方展现了最根本的才干,给定一段Javascript的代码文本,它能履行得到一个成果,并且能得到履行成果的宿主言语的表明方式。

Javascript和Golang之间的交互分红两个方面:Golang向Javascript引擎中注入一些上下文,例如注册一些大局函数供Javascript运用,创立一个目标等;Golang从Javascript引擎中读取一些上下文,例如一个核算进程的核算成果。先看第一类。

常用的手法是,经过Runtime类型供给的Set办法在大局注册一个变量,例如

...
rts := js.New
rts.Set
rts.RunString // 4
...仿制代码
rts := js.New
o := rts.NewObject
o.Set
rts.Set
rts.RunString // 4仿制代码

切换到Golang的视角,是个很天然的进程,想要创立一个目标,需求在Golang中先创立一个对应的表述,然后在Javascript中才干运用。关于更杂乱的目标,嵌套就好了。

...
func log js.Value {
 str := call.Argument
 fmt.Print)
 return str
rts := js.New
console := rts.NewObject
console.Set
rts.Set
rts.RunString`) // hello world仿制代码
相较于向Javascript引擎中注入一些信息,从中读取信息则比较简略,前面的hello world中展现了一种办法,履行一段Javascript代码,然后得到一个成果。可是这种办法不行灵敏,假如想要准确的得到某个上下文,变量的值,就不那么便利。为此, goja 供给了Get办法,Runtime类型的Get办法能够从Runtime中读取某个变量的信息,Object类型的Get办法则能够从目标中读取某个字段的值。签名如下: func Get Value func Get Value 。可是得到的值的类型都是Value类型,想要转化成对应的类型,需求经过一些办法来转化,这儿就不再赘述,有爱好能够去看它的文档。

...
func log js.Value {
 str := call.Argument
 fmt.Print)
 return str
rts := js.New
console := rts.NewObject
console.Set
rts.Set
rts.RunString`) // hello world仿制代码

经过require加载一段Commjs格局Javascript代码,直观的流程:依据文件名,读取文本,组装成一个当即履行函数,履行,然后回来module目标,可是中心能够做一些小优化,比方现已被加载过的代码, 就不从头加载,履行,仅仅回来就好了。大约的完成如下:

package core
import  string {
 return  { + c + 
}) 
func createModule *js.Object {
 r := c.GetRts
 m := r.NewObject
 e := r.NewObject
 m.Set
 return m
func compileModule *js.Program {
 code, _ := ioutil.ReadFile
 text := moduleTemplate)
 prg, _ := js.Compile
 return prg
func loadModule js.Value {
 p = filepath.Clean
 pkg := c.Pkg[p]
 if pkg != nil {
 return pkg
 prg := compileModule
 r := c.GetRts
 f, _ := r.RunProgram
 g, _ := js.AssertFunction
 m := createModule
 jsExports := m.Get
 g
 return m.Get
}仿制代码

要想让引擎能运用这个才干,就需求将require这个函数注册到Runtime中,

// RegisterLoader register a simple commonjs style loader to runtime
func RegisterLoader {
 r := c.GetRts
 r.Set js.Value {
 p := call.Argument.String
 return loadModule
}仿制代码
完好的比方有爱好可看 github.com/81120/gode

经过require加载一段Commjs格局Javascript代码,直观的流程:依据文件名,读取文本,组装成一个当即履行函数,履行,然后回来module目标,可是中心能够做一些小优化,比方现已被加载过的代码, 就不从头加载,履行,仅仅回来就好了。大约的完成如下:

package core
import  string {
 return  { + c + 
}) 
func createModule *js.Object {
 r := c.GetRts
 m := r.NewObject
 e := r.NewObject
 m.Set
 return m
func compileModule *js.Program {
 code, _ := ioutil.ReadFile
 text := moduleTemplate)
 prg, _ := js.Compile
 return prg
func loadModule js.Value {
 p = filepath.Clean
 pkg := c.Pkg[p]
 if pkg != nil {
 return pkg
 prg := compileModule
 r := c.GetRts
 f, _ := r.RunProgram
 g, _ := js.AssertFunction
 m := createModule
 jsExports := m.Get
 g
 return m.Get
}仿制代码

要想让引擎能运用这个才干,就需求将require这个函数注册到Runtime中,

// RegisterLoader register a simple commonjs style loader to runtime
func RegisterLoader {
 r := c.GetRts
 r.Set js.Value {
 p := call.Argument.String
 return loadModule
}仿制代码

之前一向分不清Javascript引擎和Javascript履行环境的边界,经过这个比方,有了一个很详细的知道。并且,对Node自身的结构也有了一个更清楚的认知。在一些场景下,需求将一些言语嵌入到另一个言语中完成一些更灵敏的功用宽和耦,例如nginx中的lua,游戏引擎中的lua,mongodb shell中的Javascipt,乃至nginx官方头供给了一个阉割版别的Javascript完成作为装备的DSL。那么在这种需求嵌入DSL的场景下,嵌入一个老练言语的履行引擎比自己完成一个DSL要简略便利得多。并且,各种场景下,对言语自身的要求也不尽相同,例如边际核算场景,嵌入式下,能够用Javascript来开发,可是是不是需求一个完好的V8呢?对环境和功能有特殊要求的场景下,约束DSL,供给必要的宿主言语扩展也是个不错的思路吧。

热门文章

随机推荐

推荐文章