はじめに
JSを久々に書くとPromiseを忘れてしまうため、見返せるように記事にしてみました。
Promiseとは
Promise オブジェクトは、非同期処理の完了 (もしくは失敗) の結果およびその結果の値を表します。
Promiseオブジェクト生成
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
Promiseを返す関数を生成
function test(time) {
// Promiseを返す
return new Promise(
(resolve ,reject) => {
setTimeout(() => {
resolve('foo');
}, time);
}
);
}
// Promiseオブジェクトを作成
const myPromise = test(300);
Promiseの連鎖
Promiseにはpromise.then()
, promise.catch()
, promise.finally()
の各メソッドが存在する。
これらは promise を返すため、メソッドチェーンとして使うことができる。
function checkMail() {
return new Promise((resolve, reject) => {
// 50%の確率で成功
if (Math.random() >= 0.5) {
resolve('Mail has arrived');
} else {
reject(new Error('Failed to arrive'));
}
});
}
checkMail()
.then((mail) => {
console.log(mail);
})
.catch((err) => {
console.error(err);
})
.finally(() => {
console.log('Experiment completed');
});
promise.then()
then()
メソッドは Promise を返します。最大 2 つの引数として、
Promise が成功した場合と失敗した場合のコールバック関数を取ります。
promise.catch()
catch()
メソッドは Promise を返しますが、失敗した場合のみ扱います。
then(undefined, onRejected) の呼び出しと同じ動作です。
簡潔に言うと例外を投げたり、rejectを返すときに使う。
promise.finally()
finally()
メソッドは Promise を返します。
Promiseが確立したら、成功か失敗かにかかわらず、指定されたコールバック関数が実行されます。
静的メソッド
Promise.all()
複数のPromiseオブジェクトをまとめて処理します。
全てのPromiseが成功するか、失敗するまで待ちます。
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
// 出力結果: Array [3, 42, "foo"]
});
Promise.resolve()
Promise.resolve()
メソッドは、与えられた値で成功した Promise オブジェクトを返します。
Promise.resolve('Success').then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 呼び出されない
});
Promise.reject()
Promise.reject()
メソッドは、引数で与えられた理由で失敗した Promise オブジェクトを返します。
function resolved(result) {
console.log('Resolved');
}
function rejected(result) {
console.error(result);
}
Promise.reject(new Error('fail')).then(resolved, rejected);
// 出力結果: Error: fail
async/awaitとは
async
および await
を使用することで、
Promiseベースの非同期の動作を、Promiseチェーンを明示的に構成する必要なく、
よりすっきりとした方法で書くことができます。
又、非同期コードに通常の try/catch
ブロックを使用することができます。
書き方の違い
下記のPromise関数を then/catch
、 async/await
で処理の違いをみる。
function test1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved1');
}, 2000);
});
}
function test2() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved2');
}, 3000);
});
}
then/catchのケース
test1()
とtest2()
が入れ子になり、ネストが深くなっている。
// 1回目
test1()
.then((result) => {
console.log(result);
// 2回目
test2()
.then((result2) => {
console.log(result2);
}).catch((e) => {
console.log(e);
});
}).catch((e) => {
console.log(e);
});
async/awaitのケース
ネストが浅くなり、見やすくなった。
(async () => {
try {
// 1回目
const result = await test1();
console.log(result);
// 2回目
const result2 = await test2();
console.log(result2);
} catch (e) {
console.log(e)
}
})()
おまけ
コールバック関数
resolve
や reject
で呼ぶ
function test(resolve , reject) {
if (Math.random() >= 0.5) {
resolve('Success');
} else {
reject('Error');
}
}
function result(value){ console.log(value); }
function error(value){ console.log(value); }
new Promise(test).then(result, error);
promiseオブジェクトを引数へ
function callfunc(fn) {
const maybePromise = fn();
// Promiseのみ許可
if (maybePromise instanceof Promise) {
return maybePromise.finally(() => {
console.log('Suceess');
})
} else {
console.log('Error')
}
}
callfunc(async () => {
try {
console.log('start');
} catch (e) {
console.log(e);
}
});
さいごに
以上です。
Promiseの静的メソッドは他にもあり、使い方もそれぞれ存在するため
改めて確認が必要だなと思いました。