JavaScriptの非同期処理に関して、前より理解が深まった気がしてるので、ひとまず現時点の理解力を記録するために記事にした。
あとから見返して、全然違うじゃん…となったらそれはそれでご愛嬌だと思うことにします。あくまで備忘録。
該当コード
この後に自分が解釈した箇所の参照として、①~⑤の番号を振っています。
コードは、独習JavaScriptテキストの内容であり、直列の非同期処理がうまく処理されないコードとされています。
let count = 0;
function promiseFactory() {
return new Promise((resolve, reject) => {
setTimeout(() => {
count++;
console.log(`${count}回目のコールです。時刻:[${new Date().toTimeString()}]`);
if (count === 3) { // 3回目のコールでエラー
reject(count);
} else {
resolve(count);
}
}, 1000);
});
}
const instance = promiseFactory(); // -------①
instance
.then(() => { return instance; }) // -------②
.then(() => { return instance; }) // -------③
.then(() => { return instance; }) // -------④
.catch(errorCount => {
console.error(`エラーに飛びました。現在のカウントは ${errorCount} です。`);
}).finally(() => {
console.log("処理を終了します。");
});
// ⑤ ==================
// > 1回目のコールです。時刻:[16:50:00 GMT+0900 (日本標準時)]
// > 処理を終了します。
// =====================
自分の解釈
-
定数の定義とともに関数の実行
→①ですでにpromiseFactory()を実行済みで、コンソールに表示される一行目はこのタイミングで実行されることによる表示。※実際に①だけ残して、開発ツールもしくはnodeコマンドを実行すると、同じ結果がコンソールに表示される。 -
始めに定義された定数の使い回し
→②③④で返されている定数instanceは①で実行されたものと変わらず、再度promiseFactory関数が実行されるわけではないので、同関数の内部にあるcountのインクリメントもconsole.log(...)も実行はされない。 -
非同期処理関数内から関数スコープ外の変数を使用するのは御法度
→then()の中でコールバック関数で返されている定数instanceをpromiseFactory()にすると、再度関数が実行されるので1,2,3回目と処理は進みますが、グローバル変数にあるトップレベルの変数などを非同期処理関数内で参照して、処理を加えるのは御法度。 -
⑤の出力結果は、resolve、rejectの条件処理とは関係ない
→理由として②③④が何も実行されない処理のためコメントアウトすると、
const instance = promiseFactory(); //
instance
.finally(() => {
console.log("処理を終了します。");
});
となり、初回のpromiseFactory()の実行によるPromiseオブジェクトの戻り値を格納した定数に、.finally()がつながっているだけの処理と変わらず、resolve,rejectの条件分岐を介さない処理と同じだと考えています。
1,2に関しては問題ないかと思うのですが、特に3,4に対するこれらの感覚、解釈は合っているのでしょうか?
私の考え方や間違いがある場合、ぜひ指摘していただけると嬉しいです。