ScratchX で非同期のコマンドブロック(Asynchronous command)を作る

[ScratchX の Extension をローカルで開発する環境を整える](http://qiita.com/mironal/items/99779c4d307fb004bee7) の続きです。

---

今回は ScratchX で非同期のコマンドブロックを作ってみたいと思います。

非同期のコマンドブロックっていきなり言われても分からないと思うのでざっくり説明します。

ScratchX の Extension では以下の5種類のブロックを作ることができます。

1. 同期コマンドブロック(Synchronous command)
  - これは `X歩動かす` ブロックのように一瞬で処理が終わるブロックのことです
  - 形状的には四角いブロックです
2. 非同期コマンドブロック(Asynchronous command)
  - これは `N秒でx座標をX、y座標をYにする` のように一瞬で処理が終わらないブロックのことです
3. 同期レポーターブロック(Synchronous reporter)
  - レポーターブロックとは値のブロックのことです
  - 同期コマンドブロックとは一瞬で値が取得できる `x座標` などブロックです
  - 形状的には楕円形のブロックです
4. 非同期レポーターブロック(Asynchronous reporter)
  - 非同期レポーターブロックは値を取得するのに時間がかかるブロックのことです
  - Scratch に元からあるブロックに該当するものがあるのか分かりませんが Web API を叩いて値を取得するときなどに使用します
5. ハットブロック(Hat block)
  - ハットブロックとは `イベント` のところにある `キーが押された時` などのブロックのことです

長くなりましたが Extension ではこれらのブロックを定義することができます。

実は前回の [ScratchX の Extension をローカルで開発する環境を整える](http://qiita.com/mironal/items/99779c4d307fb004bee7) で作ったブロックは 1の `同期コマンドブロック` です。

そして今回は 2 の `非同期コマンドブロック` を作ってみます。

### 作るもの

完成のイメージです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/ebdf303b-b7d0-e716-4133-f2a2d219bc97.png)

今回は指定した秒数待ってからログ(ダイアログ)を表示するブロックを作ります。

`wait 2 sec and log ろぐだよん` というやつです。

前回は即座にログを表示しましたが、今回は N秒待ってから表示するという動作になります。

こういう感じの動作を非同期な動作と呼びます。

## 事前準備

前回の [ScratchX の Extension をローカルで開発する環境を整える](http://qiita.com/mironal/items/99779c4d307fb004bee7) で作った環境をベースにして作業をしていきます。

環境が無い方は是非記事を参考にして整えてみてください。

## Extension を作る

前回作った `log_extension.js` を以下のコードに変更します。

主に

1. wait_log 関数を追加
2. descriptor のところを修正

をやっているだけです。 書くのが面倒だったらまるごとコピペしちゃってください。

重要なのは `wait_log` という関数の最後の `callback` という引数です。

同期処理の場合、 ScratchX は関数の最後の行が実行されれば処理が終わったと判断できます。

しかし非同期処理の場合は最後の行が実行されても処理が終わったかどうかは分かりません。

そこで `callback` という関数をを実行することで処理が終わったことを ScratchX に伝えてあげます。

今回の場合 `alert` を実行した後に `callback` を実行しているのでダイアログが閉じた後に `callback` が実行されて次のブロックに処理が進みます。

```js:log_extension.js
(function(ext) {

  // コメントは補足の説明なので書かなくてもいいです

  // Extension が終了するときに呼ばれる
  // 今は特に何もしない
  ext._shutdown = function() {};

  // Extension の状態を返す
  // デバイスが繋がっていないときにはエラーを返したりする
  // ---
  // 返す値, 表示される色, 意味
  //      0,          red, error
  //      1,       yellow, not ready
  //      2,        green, ready
  // ---
  // 今回はデバイスなどは使用しないので常に準備完了
  // ということで 2 を返します。
  ext._getStatus = function() {
    return {status: 2, msg: 'Ready'};
  };

  // wait 秒待ってから str を表示するブロック
  ext.wait_log = function(wait, str, callback) {
    setTimeout(function() {
      alert(str);
      callback();
    }, wait * 1000);
  };

  // この関数がブロック処理になります。
  ext.log = function(str) {
    // ログを出力するだけ
    alert(str);
  };

  // ブロックをどういう風に表示するかを書きます
  // ここの書き方は結構難しいので今は説明しません
  var descriptor = {
    blocks: [
      [' ', 'log %s', 'log', 'sample log'],
      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log']
    ]
  };

  // Scratch に作ったブロックを登録します
  ScratchExtensions.register('Log Extension', descriptor, ext);
})({});
```

diff はこんな感じ。

```diff
diff --git a/src/log_extension.js b/src/log_extension.js
index b5b6251..349ac6e 100644
--- a/src/log_extension.js
+++ b/src/log_extension.js
@@ -20,6 +20,14 @@
     return {status: 2, msg: 'Ready'};
   };
 
+  // wait 秒待ってから str を表示するブロック
+  ext.wait_log = function(wait, str, callback) {
+    setTimeout(function() {
+      alert(str);
+      callback();
+    }, wait * 1000);
+  };
+
   // この関数がブロック処理になります。
   ext.log = function(str) {
     // ログを出力するだけ
@@ -30,7 +38,8 @@
   // ここの書き方は結構難しいので今は説明しません
   var descriptor = {
     blocks: [
-      [' ', 'log %s', 'log', 'sample log']
+      [' ', 'log %s', 'log', 'sample log'],
+      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log']
     ]
   };
```

保存したら実際に ScratchX に読み込ませて使ってみます。

## ScratchX で使ってみる

まずはローカルサーバーを起動します。

前回と同じ手順です。

terminal で`package.json` のあるディレクトリに移動して `npm start` を実行します。

そしたら `http://scratchx.org/?url=http://localhost:8080/log_extension.js` をブラウザで開いて `I understand, continue` という緑色のボタンを押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/8f3906d4-3dd4-91db-a495-1373e3f2b3ba.png)

すると以下の画像のように `wait 1 secs and log sample log` というブロックが追加されていると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/0760764e-a037-3f0b-7f01-4e9eec6c0ba0.png)


早速以下のようにプロックを組んでみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/5125de39-d32a-23b3-c4c9-c90f35c88b8c.png)

そんでもって実行すると2秒後にダイアログが表示されます。

この2秒待ってから何か処理をする(今回はダイアログの表示)という動作が非同期な動作です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/ebdf303b-b7d0-e716-4133-f2a2d219bc97.png)

## まとめ

- 非同期な動作を行うブロックを作りました
- ブロックの関数内で `callback` を呼ぶことによって非同期処理の終了を ScratchX に伝えます

今回作ったブロックは特に有用なものではありませんが、非同期ブロックは

1. ロボットが指定した位置に移動するまで待つ
2. 通信が終わるまで待つ

などのように何か待つときに色々使えると思います。

次はレポーターブロックについて書きたいと思います。