きっかけ
最近Node.jsを触る機会があるが、言語を体系的に勉強してきたわけではないので、必要な機能から調べながら使っている。
あるとき一定時間待ってから次の処理を行うシーケンス的なことをしたいなと思って調べたところ、やりたいことは「非同期処理」と言われるようだ。次のようなサンプルコードが出てきた。
const t0 = Date.now(); // 開始時刻を取得
console.log('開始: ' + (Date.now() - t0)); // 経過時刻をあわせて出力
setTimeout(function() {
console.log('1秒後に実行されるはず: '+ (Date.now() - t0)); // 経過時刻をあわせて出力
}, 1000);
開始: 0
1秒後に実行される: 1004
あーそーゆーことね完全に理解した(画像は脳内補完願います)
よし、ちゃんと1秒後に実行された。
じゃあ処理を2段階にしてみよう。
const t0 = Date.now();
console.log('開始: ' + (Date.now() - t0));
setTimeout(function() {
console.log('1秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('2秒後に実行されるはず: '+ (Date.now() - t0));
}, 1000);
}, 1000);
開始: 0
1秒後に実行されるはず: 1003
2秒後に実行されるはず: 2004
あーそーゆーことね完全に理解した(画像は脳内補完願います)
じゃあ10個に増やしてみよう。
const t0 = Date.now();
console.log('開始: ' + (Date.now() - t0));
setTimeout(function() {
console.log('1秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('2秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('3秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('4秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('5秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('6秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('7秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('8秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('9秒後に実行されるはず: '+ (Date.now() - t0));
setTimeout(function() {
console.log('10秒後に実行されるはず: '+ (Date.now() - t0));
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
いやよく見たらクソむかつく(画像は脳内補完願います)
なんだこのネストの嵐は。
調べてみると、これはJavaScript界隈で言われているコールバック地獄というやつらしい。
更に調べてみると、イマドキのJavaScriptにはコールバック地獄を解消する方法が用意されているということがわかった。ですよねー。
Promise と async/await
コールバック地獄を解消する方法は2種類ほどあるらしい。
- Promiseを使う方法
- async/awaitを使う方法
後者のasync/awaitの方が新しくてイマドキらしい。ということで前者のPromiseは飛ばしても大丈夫かな。
というわけで、async/awaitの概要を調べてみた。
引用:async/awaitを使ったモダンな非同期処理 - Qiita
リピートミー。「async/awaitはPromiseで作られている」。
!!??
async関数はPromiseを返します。
この関数を呼び出すときにawaitを付けると、このコードはPromiseがresolvedかrejectedを返すまで停止します。
async/awaitを完全に理解するには、結局Promiseを理解しないといけないらしい
async/awaitの完全理解
この辺をじっくり読んでいろいろコードを書いて試した。
コードと解説
先程の10回待つ処理をasync/awaitを使って書くとこうなる。
const t0 = Date.now();
console.log('開始: ' + (Date.now() - t0));
asyncCall();
function wait1sec() {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
}
async function asyncCall() {
await wait1sec();
console.log('1秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('2秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('3秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('4秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('5秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('6秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('7秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('8秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('9秒後に実行されるはず: '+ (Date.now() - t0));
await wait1sec();
console.log('10秒後に実行されるはず: '+ (Date.now() - t0));
}
1秒後に実行されるはず: 1009
2秒後に実行されるはず: 2013
3秒後に実行されるはず: 3015
4秒後に実行されるはず: 4019
5秒後に実行されるはず: 5022
6秒後に実行されるはず: 6028
7秒後に実行されるはず: 7029
8秒後に実行されるはず: 8036
9秒後に実行されるはず: 9042
10秒後に実行されるはず: 10046
おまけ
async
は「エイシンク」と読むらしい。「アシンク」だと思ってた。
await
は「アウェイト」で良いらしい。