【JavaScript】非同期処理の書き方　Promise編


#はじめに
今週と来週の二回に分けてUdemyで学んだJavaScriptの非同期処理の書き方を投稿します。
今週は非同期処理実装時にコールバック地獄を回避できる**Promise**について書きます。

#非同期処理とは？
多くのプログラミング言語にはコードの評価の仕方として、**同期処理（sync）**と**非同期処理（async）**という大きな分類があります。
※並列処理は省略します。

**同期処理**はコードを順番に処理していき、ひとつの処理が終わるまで次の処理は行いません。

その為、重たい処理が間にあると、そこで大きな待ち時間が生まれ、画面の操作が一切行えないといった悪影響がでます。

**非同期処理**はコードを順番に処理していきますが、ひとつの非同期処理が終わるのを待たずに次の処理を評価します。 

つまり、非同期処理では同時に実行している処理が複数あります。

今回、以下のように料理レシピのIDとレシピ作成者をsetTimeOutを使ってコンソールに出力するという実装をします。


![Screen Recording 2020-11-15 at 10.23.33.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512863/31d2fac2-3b6a-2e65-d7fe-bce5832bb8eb.gif)


#コールバック地獄とは？
非同期処理を実装する際に気をつけたいのが、
複数のデータの読み込みが完了してから読み込んだデータに対して処理をかけたいという場合です。
以下のように処理を書くとします。


```javascript

function getRecipe(){
                setTimeout(() => {
                    const recipeID = [523, 883, 473, 974];
                    console.log(recipeID)

                    setTimeout((id) => {
                        const recipe = {title: 'Udon', publisher: 'Jacob'};
                        console.log(`${id}:${recipe.title}`);

                        setTimeout(publisher =>
                            const recipe = {title: 'Ramen', publisher: 'Tony'}
                            console.log(recipe)
                        }, 1500, recipe.publisher)
                    } ,1500, recipeID[2]);

                }, 1500);
            }
            getRecipe();
```

このようにコールバック関数が連続することを**”コールバック地獄”**と言います。
**上記コードは**

* ``深いネストにより可読性が低い``
* ``処理の追加／削除が大変``

と言えるでしょう。

**このコールバック地獄を回避できるのがPromiseです。**


#Promiseを使った書き方

```javascript

const getRelated = publisher =>{
                return new Promise((resolve, reject) =>{
                    setTimeout(pub =>{
                        const recipe = { title: 'Ramen', publisher: 'Tony' }
                        resolve(`${pub}: ${recipe.title}`);
                    }, 2000, publisher);
                });
            };

            const getIDs = new Promise((resolve, reject) =>{
                setTimeout(() =>{
                    resolve([523, 883, 473, 974]);
                }, 1500);
            });

            const getRecipe = recId =>{
                return new Promise((resolve, reject) =>{
                    setTimeout(ID =>{
                        const recipe = { title: 'Udon', publisher: 'Taro' };
                        resolve(`${ID}: ${recipe.title}`)
                    }, 2000, recId);
                });
            };

            getIDs
            .then(IDs => {
                console.log(IDs);
                return getRecipe(IDs[2]);
            })
            .then(recipe => {
                console.log(recipe);
                return getRelated('Tony');
            })
            .then(recipe => {
                console.log(recipe);
            })
            .catch(e => {
                console.log(e);
            });
```

結果は、成功と失敗の2つに分かれます。

成功時には引数で渡される関数resolveを、失敗時には引数で渡されるrejectを呼び出すように記述します。
(今回はrejectは省略)

resolve()した値はthen()で受け取れ、reject()した値はcatch()で受け取れます。

次週はpromiseよりも簡潔に書けるように導入されたasync/awaitという機能について書きます。

#参考
[Udemy: The Complete JavaScript Course 2020: From Zero to Expert! (Lecture No.434)](https://www.udemy.com/course/the-complete-javascript-course/)