wasm_exec.js 文件解读
date: 23.10.7 go version: 1.21.1
因为我是笨蛋 所以有错误请让我知道
wasm_exec.js是go官方给出的 js解释Gom编译成的 wasm 的解释代码文件
当然也有其他的wasm_exec.js比如tinygo 本文旨在帮助不太熟悉前端的人( 可能只有我 )简单的去理解它的js这边是调用运行的 至于go那边则会放在后一篇
文件位于GOROOT下的misc/wasm文件夹下
$(go env GOROOT)/misc/wasm/wasm_exec.js
0~90 行
wasm相当于一个虚拟机它可以实现包括虚拟文件系统在内的系统功能 而这前90行的内容则是 判断wasm模块是否提供了系统环境 如果没有 让则直接返回enosys(error: not implemented) 表示系统功能未实现
globalThis: globalThis是JavaScript的一个全局对象,它是全局对象window的别名。在WebAssembly(WASM)环境中,由于没有全局对象window,因此需要使用globalThis来访问全局对象 在WASM模块中,我们可以使用globalThis来访问全局对象,如访问全局变量、全局函数等。例如,在模拟的文件系统API中,我们可以使用globalThis.fs来访问模拟的文件系统对象 需要注意的是,globalThis在浏览器环境中与window对象等效,但在其他环境中,如Node.js或Web Workers中,globalThis可能与global对象等效。因此,在编写跨不同环境运行的代码时,最好使用globalThis而不是window或global对象
特殊的: 它提供了 write(异步写)和writeSync(同步写)
writeSync(fd, buf) {
outputBuf += decoder.decode(buf);
const nl = outputBuf.lastIndexOf("\n");
if (nl != -1) {
console.log(outputBuf.substring(0, nl));
outputBuf = outputBuf.substring(nl + 1);
}
return buf.length;
},
write(fd, buf, offset, length, position, callback) {
if (offset !== 0 || length !== buf.length || position !== null) {
callback(enosys());
return;
}
const n = this.writeSync(fd, buf);
callback(null, n);
},
Go.constructor(一) 95 ~ 209 行
js并不原生支持go的int64等类型 这一段主要实现了那些类型 包括( set* /get* /load* )
这些类型的实现使用的是小端法(little Endian) 即低位在前(低地址) 高位在后(高地址) 与常识的习惯相反请注意
小端法的优势: 四则运算时, 从低位每次取出相应字节运算, 最后直到高位, 最终把符号位刷新, 这样的运算方式会更高效
|
|
this._exitPromise
: 这是一个Promise
对象,用于表示WebSocket
对象的关闭状态。当WebSocket
对象被关闭时,它会被 resolved,从而触发相应的回调函数。
this._resolveExitPromise
: 这是一个函数,用于处理_exitPromise
的resolve
操作。它将_exitPromise
对象的resolve
操作转发给_resolveExitPromise
函数,以便在WebSocket
对象被关闭时能够正确处理回调函数。
this._pendingEvent
: 这是一个null
值,表示WebSocket
对象当前 pending 的事件。当WebSocket
对象接收到新的事件时,它会更新_pendingEvent
的值。
this._scheduledTimeouts
: 这是一个Map
对象,用于存储已经安排的回调函数。它存储回调函数的ID和回调函数本身,以便在指定的时间间隔内执行它们。
this._nextCallbackTimeoutID
: 这是一个整数,表示下一个可用的回调函数ID。当需要为一个新的回调函数分配ID时,它会递增_nextCallbackTimeoutID
的值。
|
|
this.mem 指代内存 在wasm环境中, 内存是一个虚拟的内存空间, 用于存储程序的变量和数据
|
|
Go.constructor(二) 210 ~ 462 行
在golang提供的wasm_exec.html中 使用go.importObject作为WebAssembly.Imports来导入模块和函数
|
|
210 ~ 462 行所描述的就是这个importObject
编译的wasm里头部那段import就是这里编成的(大概)
_gotest: 是测试类
gojs: 实现gojs包(和runtime包)里的接口的方法
以wasmExit为例
|
|
直接调用 runtime.wasmExit(0)
的命令是 go.importObject.gojs["runtime.wasmExit"](0)
它实现的是 $(GOPATH)\src\runtime\sys_wasm.go中的接口
|
|
go:wasmimport
在go1.21.1中引入一个新的指令 go:wasmimport
todo:
尝试在go中直接调用runtime.wasmExit(0)失败了 提示找不到实现 无法成功编译
Go.run 465~540行
==以下两篇来自CodeGeeX==
|
|
它是一个异步函数,用于与WebAssembly程序进行交互。这个函数的主要目的是将WebAssembly程序的内存映射到JavaScript内存,以便在WebAssembly和JavaScript之间进行数据交换
执行步骤如下:
- 函数首先检查传递给它的实例是否是
WebAssembly.Instance
类型,如果不是,则抛出一个错误。 - 将
WebAssembly.Instance
类型的实例存储在_inst
变量中。 - 创建一个
DataView
对象mem
,用于访问WebAssembly程序的内存。 - 创建一个包含一些JavaScript值(如
NaN
、0
、null
、true
、false
、globalThis
和this
)的数组_values
。这个数组将存储WebAssembly程序当前正在引用的JS值。 - 创建一个数组
_goRefCounts
,用于存储WebAssembly程序对每个JS值的引用次数。数组的所有元素都被初始化为Infinity
,表示它们被WebAssembly程序引用无穷多次。 - 创建一个
Map
对象_ids
,用于将JS值映射到唯一的引用ID。 - 创建一个空数组
_idPool
,用于存储已被垃圾回收的引用ID。 - 设置
exited
变量为false
,表示WebAssembly程序尚未退出。 - 创建一个
Promise
对象_exitPromise
,用于在WebAssembly程序退出时通知JavaScript程序。 - 将命令行参数和环境变量写入WebAssembly程序的内存。这通过创建一个
DataView
对象argv
,然后将命令行参数和环境变量添加到该对象中来完成。 - 调用WebAssembly程序的
run
函数,传递argc
和argv
参数。argc
表示命令行参数的数量,argv
是一个指针数组,其中每个指针都指向一个命令行参数或环境变量。 - 如果
exited
为true
,则调用_resolveExitPromise
函数,以通知JavaScript程序WebAssembly程序已退出。 - 等待
_exitPromise
解析,然后继续执行。
_resume()和 _makeFuncWrapper(id)
_resume()
函数用于恢复Go程序的执行。它首先检查程序是否已经退出,如果是,则抛出一个错误。然后,它调用Go程序的resume()
函数,这将执行Go程序中的代码。最后,它检查程序是否已经退出,如果是,则调用_resolveExitPromise()
函数,该函数将通知JavaScript程序Go程序已退出。
_makeFuncWrapper(id)
函数用于创建一个函数,该函数可以调用Go程序中的函数,并将结果返回给JavaScript程序。它接受一个id
参数,表示要调用的Go程序函数的ID。函数内部首先创建一个匿名函数,该函数将接收一个事件对象作为参数,该事件对象包含要调用的Go程序函数的ID、当前上下文和参数。然后,它将事件对象存储在_pendingEvent
变量中,并调用_resume()
函数来恢复Go程序的执行。最后,它返回事件对象中的结果。