在 golang 中执行 javascript 代码的方案详解

在 Golang 中执行 JavaScript 代码可以通过几种不同的方式来实现。通常,这些方法包括使用外部 JavaScript 引擎或通过调用 JavaScript 引擎的绑定库。下面是一些常用的方法:

1. 使用 otto 库(嵌入式 JavaScript 引擎)

otto 是一个纯 Go 语言编写的 JavaScript 解释器,允许在 Go 程序中直接运行 JavaScript 代码,而不需要启动外部进程。

安装 otto

go get github.com/robertkrimen/otto

示例代码:

package main

import (
    "fmt"
    "github.com/robertkrimen/otto"
)

func main() {
    // 创建 JavaScript 解释器
    vm := otto.New()

    // 执行 JavaScript 代码
    _, err := vm.Run(`
        function greet() {
            return "Hello from JavaScript!";
        }
        greet();
    `)

    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    // 获取 JavaScript 函数的返回值
    result, err := vm.Call("greet", nil)
    if err != nil {
        fmt.Println("Error calling function:", err)
        return
    }

    // 输出结果
    fmt.Println(result.String()) // 输出:Hello from JavaScript!
}

说明:

  • otto.New() 创建一个新的 JavaScript 解释器。
  • vm.Run() 用于运行 JavaScript 代码。
  • vm.Call() 用于调用已定义的 JavaScript 函数。

otto 适用于在 Go 中嵌入 JavaScript 的场景,但它的性能和支持的功能相对有限。它适合用于执行简单的 JavaScript 代码,但不适合高性能要求的复杂应用。

2. 使用 goja 库(嵌入式 JavaScript 引擎)

goja 是另一个 Go 语言实现的 JavaScript 引擎,支持 ES5 和部分 ES6 特性,适合在 Go 中嵌入 JavaScript。

安装 goja

go get github.com/dop251/goja

示例代码:

package main

import (
    "encoding/json"
    "fmt"

    "github.com/dop251/goja"
)

func main() {
    // 创建 JavaScript 运行时
    vm := goja.New()

    // 执行 JavaScript 代码:定义一个函数
    res, err := vm.RunString(`
        function greet(name) {
            return "Hello, " + name + "!";
        }
        greet("rico");
    `)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println(res)

    // 获取 JavaScript 中定义的 greet 函数
    // greetFunc := vm.Get("greet")
    // if greetFunc == nil {
    //  fmt.Println("Error: greet function not found")
    //  return
    // }

    // 调用 JavaScript 中的 greet 函数
    result, err := vm.RunString(`greet("Alice");`)
    if err != nil {
        fmt.Println("Error calling greet:", err)
        return
    }

    // 转换返回的值为 Go 字符串
    //resultValue := result.Export()

    // 输出结果
    jstr, err := json.Marshal(result)
    if err != nil {
        fmt.Println("Error with json.Marshal() :", err)
        return
    }
    fmt.Println("result 1: " + string(jstr)) // 输出:Hello, Alice!

}

说明:

  • goja.New() 创建一个新的 JavaScript 运行时。
  • vm.RunString() 用于执行 JavaScript 代码。
  • vm.Get() 用于获取 JavaScript 环境中的值。

goja 库支持较多的现代 JavaScript 特性,相比于 otto,它在性能和功能上更强大。

3. 使用 Node.js 通过 os/exec 执行外部进程

如果你希望在 Golang 中执行更复杂的 JavaScript 代码,或者需要运行 Node.js 中的脚本,可以使用 os/exec 启动 Node.js 进程执行 JavaScript 脚本。

示例代码:

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    // 定义要执行的 JavaScript 代码
    jsCode := `
        console.log("Hello from Node.js!");
    `

    // 执行 Node.js 进程
    cmd := exec.Command("node", "-e", jsCode)
    output, err := cmd.CombinedOutput()

    if err != nil {
        log.Fatal(err)
    }

    // 输出 Node.js 进程的执行结果
    fmt.Println(string(output))
}

说明:

  • exec.Command("node", "-e", jsCode) 启动 Node.js 并通过 -e 选项执行内联的 JavaScript 代码。
  • cmd.CombinedOutput() 执行命令并获取输出结果。

这种方法适用于需要执行较为复杂的 JavaScript 代码,尤其是当你需要依赖 Node.js 生态系统(例如使用 NPM 包)时。

4. 使用 WebView(嵌入浏览器)

如果你的应用程序需要在桌面应用中显示 HTML 或 Web 内容,并且包含 JavaScript 代码,可以使用 WebView 库。WebView 可以嵌入一个小型浏览器,并执行 JavaScript 代码。

安装 webview

go get github.com/webview/webview

示例代码:

package main

import (
    "github.com/webview/webview"
)

func main() {
    // 创建一个 WebView 窗口并执行 JavaScript 代码
    webview.Open("Hello", `
        <html>
            <body>
                <script>
                    alert("Hello from JavaScript!");
                </script>
            </body>
        </html>
    `, 800, 600, true)
}

说明:

  • webview.Open 创建一个浏览器窗口并执行 HTML 和 JavaScript。
  • 这对于桌面应用程序非常有用,但对于仅需执行 JavaScript 代码的后端服务来说可能不太适用。

总结

  1. ottogoja:适用于需要在 Go 内部执行简单 JavaScript 代码的场景。
  2. os/exec:适用于需要运行 Node.js 脚本或更复杂的 JavaScript 代码的情况。
  3. WebView:适用于桌面应用程序,需要在嵌入式浏览器中运行 JavaScript。

根据你的需求,可以选择适合的方式来执行 JavaScript。如果你有具体的用例或场景,我可以帮助你进一步细化解决方案。