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


関連記事

Vue on Rails で作ったアプリを振り返ってみる

1 はじめに2 全体的なこと2.1 ディレクトリ構成2.2 CSSフレームワーク2.3 Capistranoでのデプロイ3 axiosのラッパー4 Vuex4.1 ログインの状態管理5 Router6 ...

もうすぐ登場!Vue 3の変更点まとめ

1 はじめに2 仕様変更2.1 複数のv-modelが定義可能に2.2 template直下に複数のタグを記述可能に2.3 開始処理がcreateAppに2.4 scoped cssの仕様変更2.5 ...

icon

TypeScript初心者が押さえておくべき型システム

1 はじめに2 型アノテーション2.1 プリミティブ型2.2 リテラル型2.3 any2.4 nullとundefined2.5 ユニオン型2.6 交差型2.7 タプル型2.8 列挙型2.9 配列2. ...

js

JavaScriptのみでPOSTした場合のCSRFトークンの認証に関するTIPS

1 はじめに2 実装2.1 なぜエラーが発生したか2.2 修正後のコード3 さいごに はじめに RailsアプリケーションでPOSTリクエストを送る場合、多くの場合はform_withなどのヘルパーを ...

js

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

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

フォロー

blog-page_side_responsive

2021年11月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

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