接続が保たれている間、同じ処理を繰り返す
ここまでの例は、接続または切断のタイミングで1度だけ処理を行うものでした。次は、obnizデバイスと接続している間、ずっと継続して同じ処理を繰り返すプログラムを解説します。
プログラム
ソースコード
<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
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デバイスの通信が切断すると自動的に実行を停止します(切断を検知するまでに時間がかかることがあります)。
繰り返し処理
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()
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>
<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’?』という警告が出ますが気にせず実行してみましょう。
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側で処理を同期できる
コメント