今更ですがasync.jsのasync parallelをasync.jsを使わないでやるにはどうしたら良いのか疑問に思ったので試してみました。
Promise
- try-catchでは同期処理例外しかキャッチできない。(Promiseをtry-catchで囲ってもPromise内部の例外はキャッチできません)
- Promise内部で例外(throw new Error())が発生した場合には、それをrejectとして処理をします。(Promise内で発生した例外は、thenの第二引数、もしくはcatchで取得することが出来ます。)
- thenやcatch内で例外(throw new Error())が起きた場合は、暗黙的にrejectとみなされる。
- thenやcatchがPromise以外を返している場合は、暗黙的にPromise.resolveとみなされる。(thenの第一引数で取得できるが、catchはできない)
Promiseの結果を返すにはPromiseのresolveもしくはrejectを実行する。
thenはPromiseの結果を受けて実行されます。
async/await
- async functionは呼び出されるとPromiseを返す。
- async functionが値をreturnした場合、Promiseはその値をresolveする。
- async functionがエラーや何らかの値をthrowした場合はその値をrejectする。
- async functionは、await式を含むことできます。await式は、async関数の実行を一時停止し、await式のPromiseの解決を待つ。(値がPromiseではなかった場合は値を解決されたPromiseに変換して、それを待ちます。Promiseが拒否された場合、理由となった値をスローします。)
- async function内のtry-catchではPromise内部で起きた非同期処理例外もキャッチできる。
動作確認
Promise エラーなし
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("one")}, 2000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("two")}, 1000);
});
Promise.all([p1, p2]).then(results => {
console.log(results);
}).catch(reject => {
console.log(reject);
});
// ["one", "two"]
Promise エラーあり
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("one")}, 2000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("two")}, 1000);
});
const p3 = new Promise((resolve, reject) => {
reject("reject message");
});
Promise.all([p1, p2, p3]).then(results => {
console.log(results);
}).catch(reject => {
console.log(reject);
});
// reject message
async/await エラーなし
async function one() {
return "one";
}
async function two() {
return "two";
}
Promise.all([one(), two()]).then(results => {
console.log(results);
}).catch(reject => {
console.log(reject);
});
// ["one", "two"]
async/await エラーあり
async function one() {
return "one";
}
async function two() {
return "two";
}
async function three() {
throw "reject message";
}
Promise.all([one(), two(), three()]).then(results => {
console.log(results);
}).catch(reject => {
console.log(reject);
});
// reject message
補足
配列内のものは全てがPromiseである必要もありません。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("one")}, 2000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {resolve("two")}, 1000);
});
Promise.all([p1, p2, 3, "4"]).then(results => {
console.log(results);
}).catch(reject => {
console.log(reject);
});
// ["one", "two", 3, "4"]
thenのcatchのところは以下でも問題ないです。
Promise.all(配列).then(results => {
console.log(results)
}, reject => {
console.log(reject);
});
- Promise.allはawaitでも待てる
await Promise.all([p1, p2, p3]);
これは全てが解決されるもしくは1つでも拒否されたら即座に返す。
全てのPromiseの結果関係なしに全てを完了を待つ場合は以下を使います。
await Promise.allSettled([p1, p2, p3]);