Promise…そうそれは
簡単そうに思えてややこしく、困難そうに思えて容易い、そんなラララ (by Mr.Chldren)
前回の記事 JavaScriptをもうちょっと理解する54のトピック で軽く触れたPromiseについてです。
次回、Promiseについて本気出して考えてみた記事を書く予定ですが、前哨戦としてなるべく短くかみ砕いた記事を書きます。asyncとawaitに触れるにはPromiseを避けられないので、Promiseはわずかばかり丁寧に。
Promise
Promiseの発生
Promiseは自分で作るか、関数の戻り値で発生します。
- Promiseを返す主な関数は
fetchとかfs.readFileあたりだよ -
new Promise(関数)で生成することもできるよ
Promiseがもつ3つの状態
Promise の状態は3つ。処理中の pending 、成功したときの fulfilled 、失敗の rejected のいずれかです。
- 例えばfetch関数なら実行した瞬間は
pending。完了するとfulfilledかrejectedになるよ - 状態が fullfilledとrejectedのPromiseは何らかの
値を持っているよ - rejectedの持つ値は基本的には
Errorだよ
続きの処理は .then か .catch で書ける
状態が fulfilled か rejected なら続きの処理を実行できます。
- fulfilledなら
プロミス.then(処理)で。処理の第1引数には値が入っているよ - rejectedなら
プロミス.catch(処理)で。処理の第1引数には値(基本はError)が入っているよ
.then や .catch の戻り値も Promise
.thenや.catchの戻り値はPromiseです。Promiseということは、さらに.thenで続けられます。
- Promiseをreturnすれば、
returnしたPromiseがそのまま返るよ(例: fetchをreturnするなど) - Promise以外の値をreturnすれば、
状態がfullfilledで、returnした値を持つPromiseが返るよ
async
通常の(普通の)functionで値をreturnするとその値が返りますが、 async function で値をreturnすると、 状態がfullfilledで、returnした値を持つPromise が返ります。
- functionの中に
awaitを書きたい時にasync functionにするよ - functionの前(左)に
asyncを付けるだけだよ
await
Promiseでは、.thenで続きの処理を実行できると書きましたが、それをもっとシンプルに書けます。
-
状態がfulfilledなPromiseの左にawaitをつけると、PromiseそのものではなくPromiseが持っている値が返るよ- 状態がpendingの場合は、
fulfilledかrejectedになるまで待つよ -
rejectedになった場合はエラーが発生するので、普通のtry catchでエラー処理できるよ
- 状態がpendingの場合は、
-
awaitは async functionの中でだけ書くことができるよ
※ Top-Level-Awaitのことはこの記事では考えません
最後に全体のイメージをコメントで解説
// fetchのところでawaitを使いたいのでfunctionの左にasyncをつける
async function fetchArticle() {
try {
// awaitでfetchの完了を待つ&値の取り出し
const response = await fetch('Articleを取得するAPIのURL');
// .json()の戻りもPromiseだが、awaitにより値として返る
const articleJson = await response.json();
// Promiseでない値を返すが、async functionなのでこの値を持ったPromiseで返る
return articleJson;
} catch (error) {
// もしどこかでawaitの右側がrejectedになったらここに来る
console.error(error);
}
}
/**
* 使う側の例その1
* asyncなfunction(fetchArticle)がPromiseを返すので、状態がfulfilledになり次第.thenで処理する
*/
fetchArticle().then(articleJson => 処理);
/**
* 使う側の例その2
* asyncなfunctionの中から呼び出してawaitで処理
*/
async function hoge() {
// asyncなfunction(fetchArticle)が返すPromiseを、awaitで待つ&値の取り出し
const articleJson = await fetchArticle();
// 何らかの処理~~(略)
}
お気づきでしょうか。使う側の例その2、これを呼び出す側は async+await か .then のどちらかで呼び出すということに。
無限ループのようですが、非同期処理であるPromiseは結局どこかで .then(=終わり次第) で処理しなければならないのです。
まとめ
なるべく短く解説してみましたが、どうでしょう、ちゃんと短く書けたでしょうか?(そこ)
Promise、どちらかというと奥が深いようで意外にシンプルなものだと思うんですが、非同期処理に慣れないとややこしく感じると思います。この記事が少しでも何かのヒントになれば幸いです。
次回、「Promiseについて本気だして考えてみた」でお会いしましょう~(予定)
おまけ
よければF12を押して開発者ツールを開いて、Consoleで下のコードなどを試してみてください。
asyncの有無で何が変わるか確認できますよ!
function onlyFunc() {
return 1;
}
async function asyncFunc() {
return 1;
}
console.log('onlyFunc', onlyFunc());
console.log('asyncFunc', asyncFunc());