obniz との接続中、処理を繰り返す

obniz

接続が保たれている間、同じ処理を繰り返す

ここまでの例は、接続または切断のタイミングで1度だけ処理を行うものでした。次は、obnizデバイスと接続している間、ずっと継続して同じ処理を繰り返すプログラムを解説します。

プログラム

ソースコード

HTML
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/obniz@3.26.0/obniz.js"></script>
    <script>
      const obniz = new Obniz("1234-5678");
      var n=0;
      obniz.onconnect = async function() {
        obniz.onloop = async function() {
          obniz.display.clear();
          obniz.display.print(n);
          n++;
          await obniz.wait(1000);
        };
      };
    </script>
  </head>
  <body>
    <h1>loop count</h1>
  </body>
</html>

プログラムの解説

接続中に処理を繰り返す onloop
JavaScript
obniz.onconnect = async function() {
  obniz.onloop = async function() {
    obniz.display.clear();
    obniz.display.print(n);
    n++;
    await obniz.wait(1000);
  };
};

Obniz.onloop に処理を設定すると、プログラムとobnizデバイスの接続中に継続して繰り返し実行されます。今回の例では、onconnectなどと同様、処理内容を無名関数 function(){ … } で定義しています。

setInterval() や while(true) などのJavaScriptの機能を利用して独自に繰り返し処理を実装するのと違い、Obniz.onloopで定義された処理ではプログラムとobnizデバイスの通信が切断すると自動的に実行を停止します(切断を検知するまでに時間がかかることがあります)。

繰り返し処理
JavaScript
obniz.onconnect = async function() {
  obniz.onloop = async function() {
    obniz.display.clear();
    obniz.display.print(n);
    n++;
    await obniz.wait(1000);
  };
};

繰り返し処理のサンプルはごく簡単なものです。obniz.display.clear() でLCD画面をクリアしてからobniz.display.print(n) でグローバル変数 n の値を LCD に表示し、そのたびに n の値を1つインクリメントしています。

処理を待つ wait()
JavaScript
obniz.onconnect = async function() {
  obniz.onloop = async function() {
    obniz.display.clear();
    obniz.display.print(n);
    n++;
    await obniz.wait(1000);
  };
};

Obniz.wait() メソッドは、obnizデバイスに引数で指定した時間だけ処理を待機させます。引数はミリ秒単位です。この例では obniz.wait(1000) なので 1000ms = 1秒の待機です。

Obniz.wait() メソッドの返却値は、Promiseという、JavaScriptの非同期処理のための特殊なデータです。詳しくはJavaScriptでの同期/非同期処理についての書籍などをご覧下さい。awaitは同期処理のためのキーワードです。後の『プログラム3の改造&実験』で解説します。

実行

このプログラムでは、obniz基板上のLCDに数を表示し、1秒に1つずつカウントアップしていきます。

改造&実験

プログラム3を以下のように書き換えてみましょう。
(色が付いている行を追加して下さい)

改造1

HTML
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/obniz@3.26.0/obniz.js"></script>
    <script>
      const obniz = new Obniz("1234-5678");
      var n=0;
      obniz.onconnect = async function() {
        obniz.onloop = async function() {
          obniz.display.clear();
          obniz.display.print(n);
          document.getElementById("display").innerText=n;
          n++;
          await obniz.wait(1000);
        };
      };
    </script>
  </head>
  <body>
    <h1>loop count</h1>
    <div id="display"></div>
  </body>
</html>

改造1の実行

実行すると、Web画面上でもカウントを表示するようになります。通信のタイムラグでobnizデバイス上の方が少し遅れて見えますが、まぁ『一緒に』カウントしているといっていいでしょう。

改造2

ではここで、obniz.wait()の前のawaitを取ってしまいましょう。

『obniz.wait is maybe async function. Do you mean ‘await obniz.wait’?』という警告が出ますが気にせず実行してみましょう。

JavaScript
      obniz.onconnect = async function() {
        obniz.onloop = async function() {
          obniz.display.clear();
          obniz.display.print(n);
          document.getElementById("display").innerText=n;
          n++;
          obniz.wait(1000);
        };
      };

改造2の実行

今度は、obnizデバイス側が先ほどと同じく1秒に1ずつカウントしているのに対して、Web側のカウントはそれよりはるかに速く進んでいます。

こうなってしまうのには、Obniz.wait() の仕様が関係しています。

Obniz.wait() メソッドは obnizデバイスに対して指定時間の待機を指示しますが、プログラム側では obnizデバイス側とは『同期』しないのです。

JavaScriptの同期/非同期処理

同期』とは、簡単に言えば『複数のプログラムやデバイスがタイミングを合わせて一緒に動く』ことです。たとえば obniz.wait(1000) でプログラムからobnizデバイスに『1000ms待機していろ』という指示を出したとき、プログラム側もobnizデバイスの待機時間終了を待って『一緒に先に進む』ようにするのが『同期』です。

しかし実際には Obniz.wait() メソッドは『非同期』なメソッドです。つまり、プログラムからobnizデバイスに『1000ms待機していろ』という指示を出した後、プログラム側はobnizデバイスの待機時間終了を待たず、さっさと先に進んでしまうのです。

そこで、プログラム側の動作をobnizデバイス側と同期させるための仕組みが、await です。awaitキーワードを付加すると、本来は非同期に実行されるメソッドが、同期する=obnizデバイス側での処理完了を待つようになるのです。

なお、awaitキーワードを含む処理は、asyncキーワードを付加した関数内にしか記述できません。つまりこの例では、obniz.onloop = async function(){ … の部分のasyncは必須です。

まとめ

  • Obniz.onloopに処理を定義すると、obnizデバイスの接続中継続して実行される
  • awaitキーワードによってobnizデバイス側とJavaScript側で処理を同期できる

コメント

タイトルとURLをコピーしました