Golang中如何将js.Value作为参数传递给js.Global().Get

Golang中如何将js.Value作为参数传递给js.Global().Get 尝试使用 Go WebAssembly 访问浏览器 IndexedDB,通过以下代码我能够创建 indexedDB,但在尝试使用 js.Global().Get(dbx) 访问它,甚至尝试访问 this.result 时遇到了错误。

//go:build js && wasm

package main

import (
	"fmt"
	"syscall/js"
)

var dbOk, dbErr js.Func
var db js.Value

func main() {
	fmt.Println("Hello WASM")
	db = js.Global().Get("indexedDB").Call("open", "Database", 1)

	dbOk = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbOk.Release()
/* 这里我遇到了错误 */
		dbx := this.result
		fmt.Println("this is: ", dbx)
/**********************/
		js.Global().Call("alert", "ok.")
		return nil
	})
	db.Set("onsuccess", dbOk)

	dbErr = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbErr.Release()

		js.Global().Call("alert", "sorry.")
		return nil
	})
	db.Set("onerror", dbErr)
	
    /* 这行代码是错误的,无法访问 `db` */
	js.Global().Get(dbx).Call("transaction", "readwrite").Call("objectStore", "employee").Call("add", `{ id: "00-01", name: "Karam", age: 19, email: "kenny@planet.org" }`)

	c := make(chan int)
	<-c
}

我遇到的错误是:

# command-line-arguments
./wasm.go:21:14: this.result undefined (type js.Value has no field or method result)
./wasm.go:41:17: cannot use dbx (type js.Value) as type string in argument to js.Global().Get

为了将其与 JavaScript 对应起来,我希望这段 go 代码:

	dbOk = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbOk.Release()
		dbx := this.result
		fmt.Println("this is: ", dbx)
		js.Global().Call("alert", "ok.")
		return nil
	})
	db.Set("onsuccess", dbOk)

等同于这段 JavaScript 代码:

var dbx

request.onsuccess = function(event) {
    dbx = request.result;
    console.log("success: "+ dbx);
};

而这段 go 代码:

js.Global().Get(dbx).Call("transaction", "readwrite").Call("objectStore", "employee").Call("add", `{ id: "00-03", name: "Karam", age: 19, email: "kenny@planet.org" }`)

用于替换这段 JavaScript 代码:

dbx.transaction(["employee"], "readwrite")
    .objectStore("employee")
    .add({ id: "00-03", name: "Karam", age: 19, email: "kenny@planet.org" });

更多关于Golang中如何将js.Value作为参数传递给js.Global().Get的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

谢谢,效果完美。

更多关于Golang中如何将js.Value作为参数传递给js.Global().Get的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我上次遇到了一个整体性的排序问题,现在正在寻找一个真正的解决方案。

免责声明:我对 syscall/js 毫无经验,但我想我看到了问题所在:

在 Go 端你不能使用 this.result,因为 this 只是一个 js.Value,而 js.Value 类型(在 Go 中)要么没有 result 字段,要么即使有,也是未导出的(因为它是小写的),所以你无法访问它。

要访问 JavaScript 对象的属性,例如 thisresult 属性,请使用 js.Value.Get

this.Get("result")

在Go WebAssembly中,js.Value类型没有直接的字段访问方式。你需要使用Get()方法来访问JavaScript对象的属性。对于this.result,正确的访问方式是this.Get("result")

以下是修正后的代码:

//go:build js && wasm

package main

import (
	"fmt"
	"syscall/js"
)

var dbOk, dbErr js.Func
var db js.Value

func main() {
	fmt.Println("Hello WASM")
	db = js.Global().Get("indexedDB").Call("open", "Database", 1)

	dbOk = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbOk.Release()
		
		// 正确访问result属性
		dbx := this.Get("result")
		fmt.Println("this is: ", dbx)
		
		// 使用dbx进行后续操作
		dbx.Call("transaction", "readwrite").
			Call("objectStore", "employee").
			Call("add", js.ValueOf(map[string]interface{}{
				"id":    "00-01",
				"name":  "Karam",
				"age":   19,
				"email": "kenny@planet.org",
			}))
		
		js.Global().Call("alert", "ok.")
		return nil
	})
	db.Set("onsuccess", dbOk)

	dbErr = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbErr.Release()
		js.Global().Call("alert", "sorry.")
		return nil
	})
	db.Set("onerror", dbErr)

	c := make(chan int)
	<-c
}

对于第二个错误,js.Global().Get()需要字符串参数,而不是js.Value。你应该直接使用dbx.Call()来调用方法:

// 错误的方式
js.Global().Get(dbx).Call("transaction", "readwrite")  // dbx是js.Value,不是字符串

// 正确的方式
dbx.Call("transaction", "readwrite")  // 直接在js.Value上调用方法

如果你需要在回调函数外部访问数据库对象,可以使用闭包或全局变量:

//go:build js && wasm

package main

import (
	"fmt"
	"syscall/js"
)

var (
	dbOk, dbErr js.Func
	db          js.Value
	dbx         js.Value // 全局变量存储数据库引用
)

func main() {
	fmt.Println("Hello WASM")
	db = js.Global().Get("indexedDB").Call("open", "Database", 1)

	dbOk = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbOk.Release()
		
		dbx = this.Get("result")
		fmt.Println("Database opened: ", dbx)
		
		// 立即执行数据库操作
		addEmployee()
		
		js.Global().Call("alert", "Database opened successfully.")
		return nil
	})
	db.Set("onsuccess", dbOk)

	dbErr = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer dbErr.Release()
		js.Global().Call("alert", "Failed to open database.")
		return nil
	})
	db.Set("onerror", dbErr)

	// 设置onupgradeneeded回调来创建对象存储
	dbUpgrade := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		dbx := this.Get("result")
		
		// 创建对象存储
		if !dbx.Get("objectStoreNames").Call("contains", "employee").Bool() {
			dbx.Call("createObjectStore", "employee", map[string]interface{}{
				"keyPath": "id",
			})
		}
		return nil
	})
	db.Set("onupgradeneeded", dbUpgrade)
	defer dbUpgrade.Release()

	c := make(chan int)
	<-c
}

func addEmployee() {
	if !dbx.IsUndefined() && !dbx.IsNull() {
		tx := dbx.Call("transaction", "employee", "readwrite")
		store := tx.Call("objectStore", "employee")
		
		employee := map[string]interface{}{
			"id":    "00-01",
			"name":  "Karam",
			"age":   19,
			"email": "kenny@planet.org",
		}
		
		request := store.Call("add", js.ValueOf(employee))
		
		// 设置添加操作的回调
		request.Set("onsuccess", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			js.Global().Call("alert", "Employee added successfully.")
			return nil
		}))
		
		request.Set("onerror", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			js.Global().Call("alert", "Failed to add employee.")
			return nil
		}))
	}
}

关键点:

  1. 使用this.Get("result")而不是this.result来访问JavaScript对象的属性
  2. 直接在js.Value上使用Call()方法,而不是通过js.Global().Get()
  3. 使用js.ValueOf()将Go值转换为JavaScript值
  4. 确保在数据库成功打开后再执行操作
回到顶部