async/await理解のためのクイズを考えてみた (後半)
はじめに
今私は、JSの非同期処理を100%理解したいと思い、以下の学習ロードマップを参考にして学習を進めています。
JSの非同期処理を理解するために必要だった知識と学習ロードマップ
今回は、その学習ロードマップの中の「Promise チェーンの構築のアンチパターンを学ぶ」という章で紹介されていた以下の動画に取り組んでいきます。
JavaScriptのasync/await 理解してますか? 説明できますか? クイズに答えてもらって良いですか?
今回は、動画の後半を進めていきます。
問題
以下の処理を、async/awaitを利用しないで、きちんと待つ関数を作りなさいという問題です。
// node14
const test = async () => {
console.log(1);
await new Promise((resolve) => {
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
})
}
const main = async() => {
await test();
console.log(3);
}
私の予想
const test = new Promise((resolve) =>
{
console.log(1);
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
})
const main = function () {
test.then(() => {
console.log(3);
});
};
main();
- testをPromiseオブジェクトをresolveで返す。
- main関数では、
then
を使ってその結果を受け取り、成功時の処理を行う。
自分の環境で挙動を確認
ん、私の環境のコードでは、ボタンが押されてからmain関数を実行するようにしているが、ボタンを押す前にtestが動いている。これは一体どういうことだ。もう一度考えてみよう。
もう一回チャレンジ
こうだ!
const test = () => {
console.log(1);
return new Promise((resolve) => {
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
});
};
const main = function () {
test().then(() => {
console.log(3);
});
};
main();
- testは関数だから、この変数は関数で定義しないといけない。
- Promiseはオブジェクトだから、結果を伝える返り値としてPromiseを返す。
key point
ChatGPTに1つ目が間違っていた理由と、2つ目のコードの違いについて聞いてみた。
-
1つ目のコードのtestは、「Promiseインスタンス」そのものであり、new Promise(...)はその場で即時実行される。
→ だからボタンを押す前に、testの中が実行された。 -
2つ目のコードでは、testは関数になっていて、main関数からtestを呼び出した時に初めて、Promiseを作成&実行する。
→ そっか、コールバック関数にしないとダメなのか -
returnでPromiseインスタンスを返す必要がある
結構初歩的なミスだったけど、thenを使って、成功時の処理を返すというのがわかったのは偉い👏
よく間違う例として以下のコードが提示されました
const test = () => {
console.log(1);
new Promise((resolve) => {
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
});
};
const main = async () => {
await test();
console.log(3);
};
このコードだと、1,3,2で出力されてしまう。
どうして違うか考えてみる。
きちんと動いた自分のコードを比較すると以下の点が異なる
- Promiseをreturnしていない。
- mainは、awaitでtestのPromiseの結果を待っている。
ん、でもresolveでPromiseは結果を知らせてるから、いいのでは…?
Promiseインスタンス内の処理は即実行されるが、今回その中のsetTimeoutが非同期コールバック関数だから、他の処理の実行終了を待つ。
だから、3
がまず出力されるのかな。
動画内の説明
returnしていない
returnしないと、Promise結果を待っているawaitが結果を受け取れない。
答え
私の1つ目のコードが正解だった!
const test = () => {
console.log(1);
return new Promise((resolve) => {
setTimeout(() => {
console.log(2);
resolve();
}, 1000);
});
};
const main = function () {
test().then(() => {
console.log(3);
});
};
main();
まとめ
- Promiseはreturnで返さないと、awaitでは結果を受け取れない
- async/awaitを使わないとき、成功時の結果後の処理では、then()を使ってその後の処理をかく。
Discussion