JavaScript
Node

複数の非同期処理を実行して結果待つ

今更ですが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);
});