iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
2
Modern Web

謙虛,踏實的Web Assembly練習系列 第 6

[練習 05] 透過Javascript API取得Module及Instance物件

簡單包裝一下Javascript API

一般使用上,對於Module,我們只要知道他的url,然後可以取得救可以。而Instance,只要可以傳importObjects給他,然後取得Instance就可以,所以我們可以包裝一下:

(function(global) {
	let module = null;
	let url = null;
	global.Wasm = Wasm;
	function Wasm(_url) {
		url = _url;
		this.getModule = getModule;
		this.getInstance = getInstance;
		function getModule() {
			if(module === null) {
				return new Promise((resolve, reject) => {
					WebAssembly.compileStreaming(fetch(url))
					.then(_module => {
						module = _module;
						resolve(_module)
					})
					.catch(reason => reject(reason))
				});
			} else {
				return new Promise((resolve, reject) => resolve(module));
			}
		};
		function getInstance(importObjects) {
			if(module === null) {
				return new Promise((resolve, reject) => {
					getModule()
					.then(_module => {
						if(!!importObjects) resolve(new WebAssembly.Instance(_module, importObjects));
						else  resolve(new WebAssembly.Instance(_module));
					})
					.catch(reason => reject(reason))
				});
			} else {
				return new Promise((resolve, reject) => {
					if(!!importObjects) resolve(new WebAssembly.Instance(module, importObjects));
					else resolve(new WebAssembly.Instance(module));
				});
			}
		}
	}
})(window);

Javascript程式裡,是使用WebAssembly.compileStreaming()搭配Fetch API回傳的Response物件來編譯並Cache編譯好的Module。然後在呼叫getModule()時,會回傳可以取得Module的Promise。getInstance()也差不多,只是多傳給他importObjects參數。

然後就可以像這樣使用:

<html>
<body>
	<div id="panel"></div>
	<script src="../wasm_util.js"></script>
	<script>
		let m = new Wasm('test001.wasm');
		m.getInstance()
		.then(instance => document.getElementById('panel').innerHTML = instance.exports.getfour())
	</script>
</body>
</html>

為了展示,所以只是寫了一個固定會傳回4的函數輸出:

(module
	(func (export "getfour") (result i32)
		i32.const 4))

執行後就在畫面出現4
webasm0003.png

使用importObjects輸入函數

要使用importObjects輸入函數給WebAssembly使用,只要定義好importObjects物件然後在呼叫getInstance()時傳給他就可以。

例如以下的WebAssembly程式:

(module
	(func $alert (import "imports" "alert") (param i32))
	(func $getfour (result i32)
		i32.const 4
	)
	(func (export "exportFunc")
		call $getfour
		call $alert
	)
)

在輸出的exportFunc中,呼叫取得常數4的函數,然後把他傳給輸入的函數。(再次簡單說明,WebAssembly程式是一個Stack Machine,所以在call $getfour時會把結果放進堆疊,然後在call $alert時會從堆疊取出傳給他)

網頁中:

<html>
<body>
	<script src='../wasm_util.js'></script>
	<script>
	let importObjects = {
		imports: {
			alert: alert
		}
	};
	let m = new Wasm('test002.wasm');
	m.getInstance(importObjects)
	.then(instance => instance.exports.exportFunc());
	</script>
</body>
</html>

先定義好importObjects,結構要跟在WebAssembly中輸入的一致。在本例中是把alert函數傳進去,然後我們呼叫輸出的exportFunc()時,他就會呼叫alert顯示結果。

Imgur


簡單地練習了一下,明天來看怎麼使用Memory。


上一篇
[練習 04] 使用Web Assembly的Javascript API
下一篇
[練習 06] 使用Memory來實做Hello, World.
系列文
謙虛,踏實的Web Assembly練習20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
海綿寶寶
iT邦大神 1 級 ‧ 2017-12-25 17:29:50

幾篇看下來
發現自己要學習新的語言
已經沒有當年那種衝勁了

還好我是路人啦啦隊
不是參賽選手

題外話
話說今天在 LINE 裡只要寫到關鍵字
都會有動畫效果(不知道去年有嗎?)
Merry Christmas
聖誕快樂

fillano iT邦超人 1 級 ‧ 2017-12-26 09:38:09 檢舉

其實我只是寫起來自嗨,實務上不會用這麼麻煩的方式寫程式XD

寫程式也能自嗨
費大真是天生吃這行飯的
/images/emoticon/emoticon12.gif

我要留言

立即登入留言