setTimeoutをタイマーとして使う/同期的に使う
約1秒(1000ミリ秒)ごとに、「Hello」と「world!」を表示させるには、次のようにする。
※Node.js v8.9.3 および Google Crome v63.0.3239.132 にて動作確認
async / await を使った場合
// 1秒待ったあと、Hello と表示する関数 function hello(){ return new Promise((resolve, reject) => { setTimeout(()=>{ console.log('Hello'); resolve(); }, 1000); }); } // 1秒待ったあと、world! と表示する関数 function world(){ return new Promise((resolve, reject) => { setTimeout(()=>{ console.log('world!'); resolve(); }, 1000); }); } // 関数hello と関数world を続けて実行する。 async function myFunc(){ await hello(); await world(); } myFunc(); // 1秒待機 // Hello // 1秒待機 // world!
promise を使った場合
// 1秒待ったあと、Hello と表示する関数 function hello(){ return new Promise((resolve, reject) => { setTimeout(()=>{ console.log('Hello'); resolve(); }, 1000); }); } // 1秒待ったあと、world! と表示する関数 function world(){ return new Promise((resolve, reject) => { setTimeout(()=>{ console.log('world!'); resolve(); }, 1000); }); } // 関数hello と関数world を続けて実行する。 hello() .then(world); // 1秒待機 // Hello // 1秒待機 // world!
動作は、
- hello() を実行
- hello関数内のresolve()が実行され、次の関数(ここではworld())が実行される。
カギとなるのは、setTimeout内のresolve()
。
これが実行されると、then
で指定された次の関数が実行されます。
setTimeout について
setTimeoutは、以下のように記述します。
setTimeout(実行する関数, 待機ミリ秒); 例: 1秒後にHello world! と表示する setTimeout(()=>{ //無名関数を使用している console.log('Hello world!'); }, 1000);
とすると、上記の例は以下のように書けると思われる。
// 1秒待ったあと、Hello と表示し、続けて // 1秒待ったあと、world! と表示する関数 // *** この実装では思ったようには動かない *** function Helloworld(){ setTimeout(()=>{ console.log('Hello'); }, 1000); setTimeout(()=>{ console.log('world!'); }, 1000); } Helloworld(); // 期待する動作 // Hello // world! // 1秒後
しかしこの場合、Hello とworld は、コード実行の約1秒後に、同時に表示される。 これは、次のような動きをしているからである。
- Helloworld() を実行
- 最初のsetTimeoutが、1秒後に実行されることを予約
- 1秒を待たずに次の処理に移る
- 2番目のsetTimeoutが、1秒後に実行されることを予約
- 1秒を待たずに次の処理に移る。処理が無いので動作を終了する。
- 予約された2つの setTimeoutが、1秒後に実行される
待機するよう設定された時間を待たずに次の処理へ移る、このような動作を「非同期的」という。
非同期的な動きをするsetTimeoutを、順に実行させたい(同期的に動作させたい)場合、
promise
やasync / await
といった、非同期動作を制御する仕組みを使用する必要がある。