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


関連記事

JQueryとmark.jsでマークダウンのリアルタイムプレビューをつくる

1 はじめに1.1 環境2 mark.js2.1 公式ドキュメント2.2 インストール2.3 実際に使用してみる2.4 オプションについて3 プレビュー機能3.1 vue.jsに関して3.2 JQue ...

react-icon

React Big Calendarの複数タイムゾーン対応

1 はじめに2 端末のタイムゾーンのみに対応する場合3 複数のタイムゾーンに対応する。3.1 日時を指定のタイムゾーンに変換する3.2 イベントの開始日時・終了日時を動的に設定する3.3 ラップクラス ...

Vue.jsとRailsでTODOアプリのチュートリアルみたいなものを作ってみた【2018.03.24】

1 はじめに1.1 作るもの1.2 前提条件、及び環境1.3 Webpack について2 準備2.1 Rails + Vue.jsのプロジェクトを作成する2.2 Vue.jsの表示確認2.3 devサ ...

SWRを使ってみた①

1 はじめに2 概要3 使い方4 主な特徴4.1 自動再検証4.2 重複排除4.3 ステート管理5 さいごに6 おすすめ書籍 はじめに 最近、React用ライブラリのSWRを触る機会があったので備忘録 ...

Next.jsのMetadataとOGP (with AppRouter)

1 はじめに2 Metadataとは?3 動的に設定するには4 OGP画像4.1 カスタムフォント5 netlifyへデプロイ6 さいごに7 おすすめ書籍 はじめに 今回はNext.jsでApp Ro ...

フォロー

blog-page_side_responsive

2021年11月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

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