度々忘れてしまうので、JavaScriptの非同期処理で使用するPromiseとasync/awaitの用途について簡単にまとめました。
非同期処理
非同期処理を簡単に表すと、以下のように処理が実行されている間に他の処理を実行させるような事をいいます。
let a = 0;
setTimeout(() => {
a = 1
}, 1000);
// 出力: 0
console.log(a);
Promise
上の非同期処理の例ではconsole.log(a)の出力では0が返ってきていましたが、非同期処理実行後の結果をlogで出力したいとします。
そういった場合に、処理をチェーンのように繋げて、前の処理が終わったタイミングで他の処理を実行させたいような場合に使用するのがPromiseです。
成功パターン
let a = 0;
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve();
}, 1000);
}).then(() => {
// 出力: 1;
console.log(a);
});
// 出力: 0;
console.log(a);
Promiseの引数にはコールバック関数が入り、その関数の引数にはresolve, rejectが入ります。
.thenで繋げた処理に関しては、Promiseのコールバック内でresolve()が発火したタイミングで処理が移ります。
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a);
}, 1000);
}).then((b) => {
// 出力: 1;
console.log(b);
});
また、このようにresolveの引数に値を入れてあげると、thenの中のコールバック関数の引数に値が渡ってきます。
失敗パターン
new Promise((resolve, reject) => {
setTimeout(() => {
reject();
}, 1000);
}).catch(() => {
console.log('error');
});
処理が失敗した場合などにはPromiseのコールバック関数内に定義した第二引数のrejectを実行します。そうする事で今度は.thenではなく.catchが実行されます。
また、thenと同様に引数を渡す事も可能です。
async/await
簡単にいうとPromiseをさらに簡略化したものになります。
let a = 0;
// 出力: 0
init();
function init() {
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a);
}, 1000);
});
console.log(a);
}
上記のような場合、thenで繋いでいなければ、init関数内のconsole.log(a)は先に出力されてしまいます。
let a = 0;
// 出力: 1
init();
async function init() {
await new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a);
}, 1000);
});
console.log(a);
}
ただこのようにawaitをPromise処理の前に書く事で、その処理が実行するまで先の処理は実行されないようにすることができます。また、awaitを関数内で使用する場合には、関数定義の際にasyncを入れてあげる必要があります。