FrontEnd

Go WebAssemblyでPromiseを使って非同期化してみた

投稿日:

はじめに

先日WebAssemblyに入門して、実際に以下のチュートリアルを進めながら、WebAssemblyを使用してブラウザ上でGoを動かすことができました。

GoでWebAssemblyに触れよう
https://golangtokyo.github.io/codelab/go-webassembly/

ただ、このチュートリアルをベースにGoの処理を書いていくと気が付くのですが、Goの処理が完了するまでJavaScriptの処理が止まってしまいます。そこで、Goを非同期化させたいと思います。
もし、初めてGoでのWebassemblyに触れる方は、初めに上記のチュートリアルに触れておくことをおすすめします。

Go WebAssemblyで非同期化のコード

js.FuncOf() で定義した関数が、JS側から呼び出されると、Go側での処理が完了するまで、JSのイベントループはブロックされます。これを回避するためには、Go側の関数で新たなgoroutineを開始する必要があります。今回は画像をWeb上からダウンロードしてブラウザ上に表示するというサンプルコードで説明します。

まずはGo側です。

このように、goroutineで処理することによって、JavaScriptのイベントループを止めることなく、非同期処理を行うことができます。
ダウンロードした画像をJavaScript側に渡すため、JavaScript側から第二引数にコールバック用の関数を渡してもらうようにしています。この関数を実行するには Invoke()関数を使用します。
Invoke()関数に引数を渡すと、そのままJavaScriptに渡すことができるので、サンプルでは callback.Invoke(outputBytes) という形でダウンロードしたデータを渡しています。

次に、HTML側です。

先ほどgo側で定義したように、download関数の第一引数に画像のURL、第二引数にはコールバック用の関数を渡します。コールバック用の関数では、第一引数に画像データが渡ってくるので、これを受け取ってimgタグとして表示しています。

このように、goroutineを使うことでJavaScriptと非同期で連携することができます。JavaScript側からのインターフェイスとしては、通常の非同期処理と同じであることも分かりました。それでは、この非同期化処理をいよいよPromise化したいと思います。

Promise化する

先ほどのコードをPromise化するため、download関数を次のように変更します。

ポイントを紹介します。

  • js.Global().Get("Promise").New(handler) でPromiseを生成することができます。これは、JavaScriptで new Promise(handler) を実行しているのと全く同じです。
  • handlerは jsFuncOf() で生成したJavaScriptの関数を渡します。
  • handlerが呼び出されると、通常のPromiseと同じように、第一引数にresolve、第二引数にrejectが渡されるので、非同期処理後にコールバックすることができます。

最後に、JavaScript側をPromiseに対応したコードに変更します。

画像を一気にダウンロードして、全て完了したら「ダウンロード完了」と表示するようにしています。
download(url) が、Go側で生成されたPromiseを返すので、thenやawaitを使うことができます。

おまけ

ダウンロードしたデータはGoでは []byte 型になりますが、これをそのままJavaScriptが側に渡すと InvalidValueエラーとなります。そこで、 js.CopyBytesToJS() 関数を使って、 []byte から Uint8Array に変換する必要がありました。
また、 js.CopyBytesToJS() の引数には、コピー先の Uint8Array を渡す必要があるため、あらかじめ空の Uint8Array を渡しています。
ちなみに、これとは逆の変換をするには、 js.CopyBytesToGo() を使い、JavaScriptの Uint8Array[]byte に変換することができます。

さいごに

GoでWebassemblyを使うユースケースがあまり思い浮かばないのですが、今後のアップデートでもっと用途が広がるかもしれません。今はまだ局所的な組み込みが現実的なのかなと思いました。

おすすめ書籍

改訂2版 みんなのGo言語 スターティングGo言語 (CodeZine BOOKS)

blog-page_footer_336




blog-page_footer_336




-FrontEnd
-, ,

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

js

JSで緯度経度情報から住所を取得する

1 はじめに2 キーを取得する2.1 キーを取得する3 コード4 参考5 さいごに はじめに Google Maps JavaScript APIを利用して、緯度経度の数値から住所を検索する方法を紹介 ...

laravel logo

Inertia使ってみた①

1 はじめに2 Inertiaとは3 ルーティング4 LaravelからReactに値渡し5 レスポンス5.1 初回5.2 page object5.3 2回目以降5.4 リロード時6 さいごに7 お ...

js

Vue.jsをTypeScriptで安全に開発するためのtsconfig.json

1 はじめに1.1 開発環境1.2 プロジェクト作成時点のtsconfig.json2 include3 exclude4 compilerOptions4.1 コンパイル系オプション4.1.1 ta ...

Vue.js入門その6〜RouterとComponentを使ってTODOアプリを修正〜

1 はじめに2 vue-routerのインストール3 サーバーサイドの改修3.1 APIに詳細(show)を追加3.2 元となるビューファイルを作成3.3 ルーティングの修正4 Vue.jsの実装4. ...

react-icon

React Konvaのソースコードを読む

1 はじめに2 React Konvaの大まかなアーキテクチャ3 コンポーネントがCanvas描画に変換される仕組み3.1 Stageコンポーネント3.2 StageWrap3.3 KonvaRend ...

フォロー

blog-page_side_responsive

2021年11月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。