Help us understand the problem. What is going on with this article?

4歳娘「パパ、Promiseやasync/awaitって何?」〜Promise編〜

スペシャルサンクス

@sega_yuu
@frodo821

とある休日

娘(4歳)「ねえパパ」

ワイ「なんや、娘ちゃん?」

娘「非同期って何?」

ワイ「ひ、非道鬼!?

娘「そうそう、非同期処理とかいうやつ」

ワイ「非道鬼処理やて・・・!?」

非道鬼「ヴォ〜〜〜!!!」

娘「!?」
娘「・・・現れたわね、非道鬼」
娘「処理してあげる」

ワイ「娘ちゃん、まだ4歳なのに、もう厨二病か・・・?」

よめ太郎「おい」
よめ太郎「お前まさか、非同期も知らんのか・・・?」

ワイ「いやいや、まさかまさか」
ワイ「流石に知っとるわ」
ワイ「それはそれは・・・極悪非道な・・・鬼のことや・・・」

よめ太郎「お前が非道鬼に喰われてしまえ

非同期処理とは

よめ太郎「ええか、娘ちゃん」
よめ太郎「まず、同期って言葉は」
よめ太郎「タイミングが合うって意味や」

娘「じゃあ、非同期っていうのはタイミングが合わないってこと?」

よめ太郎「せや」

娘「なんかピンとこないね・・・」

よめ太郎「ほな、例を挙げて説明するわ」

例えば、カウントダウンする処理

よめ太郎「ほな、例として」
よめ太郎「5、4、3、2、1、0って感じで」
よめ太郎「カウントダウンする処理を書いてみるで」

娘「うん」

よめ太郎「まず↓こんな感じのコードを書いてみたで」

JavaScript
setTimeout(() => console.log(5), 1000);
setTimeout(() => console.log(4), 1000);
setTimeout(() => console.log(3), 1000);
setTimeout(() => console.log(2), 1000);
setTimeout(() => console.log(1), 1000);
setTimeout(() => console.log(0), 1000);

よめ太郎「↑このコードを実行するのに、合計で何秒かかると思う?」

娘「ええと、setTimeout()は確か」
娘「タイマーをセットするメソッドだから」
娘「1,000ミリ秒後・・・つまり1秒後にconsole.log(5)が実行されるよね」

よめ太郎「せやな」

娘「その後、次の行が処理されるから」
娘「また1秒経過して、今度はconsole.log(4)が実行される」
娘「5、4、3、2、1、0・・・だから」
娘「合計6秒かかる!」

よめ太郎「・・・って思うやろ?」
よめ太郎「実は1秒しか掛からへんねん」

娘「そうなんだ・・・!」

よめ太郎「1行目のsetTimeout()に渡した関数は」
よめ太郎「1秒後に実行される訳やけど」
よめ太郎「その1秒間を待たずに、次の行が実行されてしまうねん」

娘「へえ〜」

よめ太郎「それが非同期処理やな」

娘「つまり・・・」
娘「1行目の処理が終わったら、2行目」
娘「2行目の処理が終わったら、3行目」
娘「そんな風にちゃんとタイミングを合わせて処理してくれるのが」
娘「同期的な処理で」

よめ太郎「そうそう」

娘「前の処理の完了を待たずに、次の処理が走るのが」
娘「非同期処理なんだね」

よめ太郎「その通りや」
よめ太郎「そして、さっきのsetTimeout()は」
よめ太郎「非同期的に処理されるメソッド、ってことやな」

娘「なるほどね〜」

よめ太郎「ほかにも、外部APIからデータを取得する処理なんかも非同期やな」
よめ太郎「例えばQiitaのAPIからデータを取得しようとして・・・」

  1. QiitaのAPIから、やめ太郎のフォロワーさん達の一覧を取得して、変数に格納する。
  2. フォロワーさん達を、リストとして画面に表示する。

よめ太郎「↑こんな処理をしようとした場合に」
よめ太郎「非同期処理のことを考えずにコードを書いてしまうとマズいんや」

JSくん「よっしゃ、QiitaのAPIに通信開始や!」
JSくん「そして、すぐさまフォロワーさんの一覧を表示や!」
JSくん「このfollowersいう変数に入っとるはずやな!」
JSくん「あれ?何も入っとらんで!」
JSくん「あかん、エラーや!!!」

よめ太郎「そらせやろ」
よめ太郎「まだ通信中や!」

よめ太郎「↑こんな感じになってしまうんや」

娘「なるほどー」
娘「APIとの通信とかって、何ミリ秒かかるのか予測できないから」
娘「完了を待たずに次の処理をしてくれようとしちゃうんだね」

よめ太郎「せやな」
よめ太郎「setTimeout()もそんな感じで」
よめ太郎「1秒待ってる間にも、次のコードを実行しようとしてしまうんや」

娘「同期が取れてないんだねぇ」

じゃあ、どうやってカウントダウンするの?

娘「でもさあ」
娘「それなら、どうやってカウントダウン機能を実装するの?」

ワイ「そこはワイに任しとき!」
ワイ「要はタイミングが合うように書いてやればええんや」

JavaScript
setTimeout(() => {
    console.log(5);
    // ここに次の処理を書く。
}, 1000);

ワイ「↑こんな感じや」

娘「どういうこと?」

ワイ「ええとな」
ワイ「setTimeout()の第一引数には、1秒後に実行したい関数を渡すやろ?」

娘「うん」

ワイ「引数として渡される関数・・・つまりコールバック関数やな」
ワイ「そのコールバック関数の中に、次にやりたい処理も書いてやるんや」
ワイ「上のコードで言うと、console.log(5);が実行された直後の部分に」
ワイ「次の処理も追加で書いてやればええんや」

娘「なるほどね」
娘「1秒経って、console.log(5);が実行された後で」
娘「次の処理が走るように、ってことかぁ」
娘「じゃあ、そこに次のsetTimeout()を書けばいいんだね!」

ワイ「そうそう」
ワイ「せやから次は・・・」

JavaScript
setTimeout(() => {
    console.log(5);
    setTimeout(() => {
        console.log(4);
        // ここに、更に次の処理を書く。
    }, 1000);
}, 1000);

ワイ「↑こうやな」
ワイ「こんな感じで、どんどん入れ子にしてやればええねん」

娘「なるほどー」
娘「パパ、すご〜い!」

ワイ「最終的には↓こうや!」

JavaScript
setTimeout(() => {
    console.log(5);
    setTimeout(() => {
        console.log(4);
        setTimeout(() => {
            console.log(3);
            setTimeout(() => {
                console.log(2);
                setTimeout(() => {
                    console.log(1);
                    setTimeout(() => {
                        console.log(0);
                    }, 1000);
                }, 1000);
            }, 1000);
        }, 1000);
    }, 1000);
}, 1000);

娘「あれ?なんか・・・」
娘「地獄みたいに読みづらいコードになっちゃったけど・・・」

よめ太郎「コールバック地獄いうやつやな」

娘「このコールバック地獄に非道鬼が住んでるの?」

ワイ「せや」

よめ太郎「ムチャクチャ言うなや」
よめ太郎「せっかく娘ちゃんが理解しかけてたのに」
よめ太郎「非道鬼の話に戻ってしまったやないか」

ワイ「いやいや、綺麗なコードやと思うで」
ワイ「見てみい」

スクリーンショット 2020-05-16 12.26.37.png

ワイ「天使が持ってるハープみたいやで」
ワイ「地獄どころか、天国や」
ワイ「ワイは好きやけどな〜」

よめ太郎「そんなに好きなら貴様を天国に送ったるわ

ワイ「ひ、非道鬼ィ!

よめ太郎「誰が非道鬼や」

娘「(なんだこの家・・・)」

それじゃあ、どうやって書けばいいの?

娘「で、結局どうすればいいの?」
娘「コールバック地獄にならないように、うまく非同期処理を繋げられる方法があるの?」

よめ太郎「あるで」
よめ太郎「Promiseとかasync/awaitやな」

娘「ふーん」
娘「パパ、Promiseやasync/awaitって何?

ワイ「(いや何でワイに聞くねん)」

Promise、async/awaitとは

ワイ「プロミス・・・つまりやな」
ワイ「消費者金融にお金を借りに行く前に」
ワイ「a think
ワイ「いったん考えるんや」
ワイ「気軽に何十万も借りると、後から大変なことになってまうからな」

娘「そっか」

ワイ「そして、await
ワイ「審査の間は大人しく待つんや」

よめ太郎「結局申し込んどるやないかい」

よめ太郎「代われ、わしが説明する」
よめ太郎「まずはPromiseからや」

Promiseとは

よめ太郎「Promiseを使うと、連続した非同期処理を書くときにも」
よめ太郎「ネスト地獄にならずにフラットに書けるんや」

娘「へぇ〜」
娘「どんな風に使うの?」

よめ太郎「new Promise()って感じで」
よめ太郎「promiseオブジェクトを生成するんや」

娘「promiseオブジェクト・・・」

よめ太郎「せや」

娘「よく分かんないけど、setTimeout()はどこに書くの?」

よめ太郎「new Promise()するときに、引数としてコールバック関数を渡すんやけど」
よめ太郎「そのコールバック関数の中にsetTimeout()とかを書くんや」

娘「またコールバック・・・?」
娘「連続して処理すると地獄になっちゃわない・・・?」

よめ太郎「大丈夫や」
よめ太郎「やってみるで」
よめ太郎「new Promise()するときにコールバック関数を渡すから・・・」

JavaScript
const promiseObj = new Promise(() => {});

よめ太郎「↑こんなイメージやな」
よめ太郎「こんな感じでpromiseオブジェクトを生成して、変数に格納するイメージや」

娘「うん」

よめ太郎「ほんで、そのコールバック関数の中に」
よめ太郎「setTimeout()とかconsole.log(5)を書くわけやから・・・」

JavaScript
const promiseObj = new Promise(() => {
    setTimeout(() => {
        console.log(5);
    }, 1000);
});

よめ太郎「↑こんな感じや」
よめ太郎「この時点でsetTimeout()は実行されて」
よめ太郎「1秒タイマーが開始されるんや」

娘「じゃあ、1秒後にconsole.log(5)が実行されるんだね」
娘「じゃあ、次のsetTimeout()とかconsole.log(4)はどこに書くの?」

よめ太郎「console.log(5)次に処理したい内容は」
よめ太郎「promiseオブジェクトが持ってるthen()メソッドに渡して登録するんや」
よめ太郎「コールバック関数としてな」

JavaScript
promiseObj.then(() => {
    setTimeout(() => {
        console.log(4);
    }, 1000);
});

よめ太郎「↑こんな感じや」

娘「ふーん」

よめ太郎「でも、then()メソッドに渡すだけでは」
よめ太郎「次にやりたい処理は実行されへんねん」
よめ太郎「まだ登録されただけや」

嫁「じゃあどうやって実行するの?」

よめ太郎「最初にnew Promise()に渡してあったコールバック関数あるやろ?」

娘「うん」
娘「最初に渡したやつね」
娘「setTimeout()console.log(5)が書いてあるやつ」

よめ太郎「その最初のコールバックが実行されるとき」
よめ太郎「ある引数が渡されて実行されるんや」

娘「ある引数・・・?」

よめ太郎「せや」
よめ太郎「その引数にresolveっていう名前をつけて受け取ってやるで」

JavaScript
const promiseObj = new Promise(resolve => {
    setTimeout(() => {
        console.log(5);
    }, 1000);
});

娘「resolveっていう引数には、何が入って来るの?」

よめ太郎「resolve関数や」
よめ太郎「そのresolve関数を実行すると」
よめ太郎「then()メソッドに渡したコールバック関数なんかが実行されるんや」
よめ太郎「setTimeout()とかconsole.log(4)が実行される訳や」

娘「えええ・・・?」
娘「先にnew Promise()して、後からthen()する訳でしょ?」

よめ太郎「せや」

娘「後からthen()に渡した関数が」
娘「先にPromise()に渡してあった関数の、引数の中に入って来るっていうこと?」

よめ太郎「いや、入って来るっていうか」
よめ太郎「上の方のresolveが実行されるまでは」
よめ太郎「下の方でthen()に渡したコールバック関数は実行されへん、っていうだけや」

娘「へー」
娘「下のthen()で登録した関数が」
娘「上のresolve()きっかけで発動する」

よめ太郎「そうそう」
よめ太郎「resolveが実行されると」
よめ太郎「then()で登録してあった次にやりたい処理が走る」
よめ太郎「だからresloveは、タイマー処理後に実行されるように書かんといかん」
よめ太郎「そうすることでタイミングが合うんや」

JavaScript
const promiseObj = new Promise(resolve => {
    setTimeout(() => {
        console.log(5);
        // タイマー発動後にresolve()する。
        resolve();
    }, 1000);
});

よめ太郎「↑こうや」
よめ太郎「ちなみに」
よめ太郎「同じpromiseオブジェクトで複数回then()することもできるで?」
よめ太郎「その場合、コード全体としては・・・」

JavaScript
const promiseObj = new Promise(resolve => {
    setTimeout(() => {
        console.log(5);
        resolve();
    }, 1000);
});

// then()メソッドに渡したコールバック関数は
// 上のresolveを実行したタイミングで実行される。
promiseObj.then(() => {
    setTimeout(() => {
        console.log(4);
    }, 1000);
});

// 同じpromiseオブジェクトで複数回then()することもできる。
// ↓この処理も、一番上のresolveを実行したタイミングで実行される。
promiseObj.then(() => {
    setTimeout(() => {
        console.log('もう1個!');
    }, 1000);
});

よめ太郎「↑こうやな」
よめ太郎「これで、1秒後に5がコンソールに表示されて」
よめ太郎「それから更に1秒後に4もう1個!がコンソールに表示されるんや」

娘「へえ〜」
娘「何となくだけど分かってきたかも」
娘「1つ目のsetTimeout()の中に2つ目のsetTimeout()を書くんじゃなく」
娘「1つ外に出てthen()に渡す関数のところで書けるから」
娘「連続でsetTimeout()をしてもネスト地獄にならなさそうだね!」

よめ太郎「そう!」
よめ太郎「その通りや!」

これでスッキリ書けるの?

娘「でも、コードがあんまりスッキリしてなくない?」
娘「Promiseを使って、連続した非同期処理をスッキリ書くこともできるの?」

よめ太郎「できるで」
よめ太郎「まず、new Promise()する部分は関数にしておくんや」
よめ太郎「何回も使うからな」

JavaScript
const promiseMaker = num => {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(num);
            resolve();
        }, 1000);
    });
};

よめ太郎「↑こんな感じや」
よめ太郎「console.log()に渡す数値は毎回変わるから」
よめ太郎「このpromiseMaker()の引数として渡せるようにしておいたで」
よめ太郎「引数名はnumや」

娘「このpromiseMaker()を実行すると」
娘「さっき言ってたpromiseオブジェクトが返ってくるんだね」

よめ太郎「せや」
よめ太郎「戻り値はpromiseオブジェクトやからthen()を持ってる」
よめ太郎「そしてthen()の戻り値もpromiseオブジェクトやから、またthen()を持ってる」
よめ太郎「せやからthen()の後にまたthen()を繋げて実行できるんや」
よめ太郎「使い方としては・・・」

JavaScript
promiseMaker(5)
    .then(() => promiseMaker(4))
    .then(() => promiseMaker(3))
    .then(() => promiseMaker(2))
    .then(() => promiseMaker(1))
    .then(() => promiseMaker(0));

よめ太郎「↑こうや」

娘「だいぶ非道鬼っぽさが減ったね」

よめ太郎「せや。スッキリやろ?」
よめ太郎「ちなみにこれは、さっきのとは違くて
よめ太郎「同じpromiseオブジェクトで複数回then()してる訳ではないで」

娘「そうなんだ」
娘「さっきと違って」
娘「毎回新しいpromiseオブジェクトが作られてるってこと?」

よめ太郎「せや」
よめ太郎「全体の流れとしては・・・」

  1. promiseMaker(5)を実行する。
    • promiseオブジェクトが生成される。
    • その時点でsetTimeout()が実行される。
    • 「未来にresolve()を実行するとき、then()で登録した処理も実行するからね」
      という約束がなされる。
  2. setTimeout()で予約された処理が、1秒後に発動。
    • console.log(5)が実行される。
    • resolve()が実行される。
  3. 約束通り、then()に登録してあったpromiseMaker(4)が実行される。

    • またpromiseオブジェクトが生成される。
    • ここで2つ目のsetTimeout()が実行される。
    • 「未来にresolve()を実行するとき、then()で登録した処理も実行するからね」
      という約束が成される。
  4. 二つ目のタイマー処理が発動する。

    • console.log(4)が実行される。
    • resolve()が実行される。
  5. resolve()きっかけで、今度はpromiseMaker(3)が実行され・・・

よめ太郎「↑この繰り返しやな」
よめ太郎「これをPromiseチェーンて呼ぶんや」

娘「へぇぇ」

よめ太郎「処理の流れを追いたい人のために」
よめ太郎「promiseMaker()関数を作らずに、愚直に書いた場合のコードも置いておくわ」


関数化しなかった場合のコード
JavaScript
new Promise(resolve => {
    setTimeout(() => {
        console.log(5);
        resolve();
    }, 1000);
})
    // ↓このthen()に渡した関数は、1つ上のresolve時に実行される。
    .then(() => {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(4);
                resolve();
            }, 1000);
        });
    })
    // ↑ここの戻り値はpromiseオブジェクト。
    // そのため続けてthen()メソッドを呼べる。
    // ↓このthen()に渡した関数は、1つ上のresolve時に実行される。
    .then(() => {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(3);
                resolve();
            }, 1000);
        });
    })
    // ↑ここの戻り値はpromiseオブジェクト。
    // そのため続けてthen()メソッドを呼べる。
    // ↓このthen()に渡した関数は、1つ上のresolve時に実行される。
   .then(() => {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(2);
                resolve();
            }, 1000);
        });
    })
    // ↑ここの戻り値はpromiseオブジェクト。
    // そのため続けてthen()メソッドを呼べる。
    // ↓このthen()に渡した関数は、1つ上のresolve時に実行される。
    .then(() => {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(1);
                resolve();
            }, 1000);
        });
    })
    // ↑ここの戻り値はpromiseオブジェクト。
    // そのため続けてthen()メソッドを呼べる。
    // ↓このthen()に渡した関数は、1つ上のresolve時に実行される。
    .then(() => {
        setTimeout(() => {
            console.log(0);
        }, 1000);
    });

外部APIからデータを取得する例

よめ太郎「APIからデータを取得するときなんかも」
よめ太郎「非同期的に処理されるから」
よめ太郎「連続してやろうとするとコールバック地獄になる可能性があるんやけど」
よめ太郎「でも、Promiseを使えば大丈夫や」
よめ太郎「外部APIから何らかのユーザー情報を取得する例で説明するで?」

JavaScript
const promise = new Promise(resolve => {
    getApiData('http://api.example.com/user/1', response => resolve(response.userData));
    // APIからデータを取得できたら、resolveを実行する。
})
    .then(userData => nextFunc(userData));
    // resolve実行時に渡した引数がuserDataに入って来る。

よめ太郎「↑こんな感じで1回外に出て
よめ太郎「then()に渡す関数のところで次の処理を書けるから」
よめ太郎「ネスト地獄にはならへんのや」
よめ太郎「例えAPIを連続で叩いてもな」

娘「へえ〜」
娘「っていうか、resolve()実行時に引数を渡せるんだね」

よめ太郎「そうやで」
よめ太郎「むしろresolve()に引数を渡すことの方が多いで」
よめ太郎「外部APIからデータを取得して、そのデータをresolve()に渡す」
よめ太郎「そのデータを受け取るためには」
よめ太郎「then()に渡す関数も、引数としてそのデータを受け取るように書いてやらなあかん」

JavaScript
    .then(userData => nextFunc(userData));

よめ太郎「↑こんな感じや」

娘「そっか」
娘「resolve()実行時に渡した引数が」
娘「このuserDataっていう引数に入って来るんだね」
娘「無理やり擬人化すると・・・」

※このセクションはイメージです。

プロミスくん「ああ〜、早く生まれたいな〜」
プロミスくん「ねぇ、そこの4歳娘ちゃん!」
プロミスくん「ワイを生成してや!」
プロミスくん「お役に立てるかもしれんで!」

娘「いいけど、何の役に立ってくれるの?」

プロミスくん「連続した非同期処理の扱いが得意や!」
プロミスくん「連続してAPIを叩く系の処理とか、上手く扱えるで!」

娘「え?助かる!」
娘「ちょうど連続してAPIを叩きたかったの!」
娘「プロミスくん、生成したい!

プロミスくん「おお、もうすぐワイも誕生できるんやな!」
プロミスくん「ちなみに、どんな非同期処理を扱ってほしいの?」

娘「えっとね」
娘「↓この案件を扱ってほしいの!」

  • APIからデータを取得してくる。
  • 無事データを取得してこれたら、そのデータを元に2つ目のAPIを叩きたい。

プロミスくん「APIからデータを取ってこれたら」
プロミスくん「次はそのデータを元に別のAPIを叩きたい感じか!」
プロミスくん「よっしゃ!この案件、ワイが扱うで!」

娘「ありがと!」

プロミスくん「ほな、まず1つ目のAPIを叩く処理を関数として書いて」
プロミスくん「それをコールバック関数として渡しながらワイを生成してくれ!」

娘「分かった!」
娘「はい!コールバック関数を書いたよ!」

プロミスくん「あ、そのコールバック関数を実行するときに」
プロミスくん「resolveってものを渡すから」
プロミスくん「resolveを受け取って実行するように書いといてくれ!」

娘「resolveを受け取って、実行する・・・」
娘「実行する、ってことはresolveは関数なんだね!」

プロミスくん「せや!」

娘「分かった!ちょっと書き換えるね!」
娘「でもresolveはどのタイミングで実行するように書けばいいの?」

プロミスくん「APIデータ取得完了後に」
プロミスくん「resolve(apiData)って感じで実行するように書いてくれ!」

娘「データ取得完了後にresolve(apiData)ね!」
娘「そこは自分で書かなきゃいけないんだね!」
娘「はい!そういう関数に書き換えたよ!」

プロミスくん「ほな、その関数を渡して、ワイを生成してくれ!」

娘「出でよ!プロミスくん!」

プロミスくん「やっと誕生できたわ!」
プロミスくん「これで、無事データが取って来れた暁には」
プロミスくん「そのデータがresolve()経由で次の処理に渡るで!」

娘「約束だからね!」

プロミスくん「おう!無事データが取れたらな!」

娘「了解!」
娘「あれ、でもまだ2つ目のAPIを叩く処理の内容を伝えてないよ!」

プロミスくん「せや!」
プロミスくん「ほな、続きの処理の内容を関数として書いて
プロミスくん「ワイのthen()メソッドに渡してや!」

娘「分かった!続きの処理then()メソッドに渡すね!」
娘「1つ目の処理のその後に実行したい処理だから」
娘「then()メソッド、っていう名前なんだね!」

プロミスくん「せや!」

娘「・・・はい!続きの処理の関数も書けたよ!」
娘「この関数は、最初のAPIデータを引数として受け取って」
娘「それを元に2つ目のAPIを叩く・・・」
娘「そんなテイで書いたよ!」

プロミスくん「それでオッケーや!」
プロミスくん「これをワイのthen()メソッドに登録しておくで!」
プロミスくん「これで、最初のAPIからデータが取れた場合」
プロミスくん「そのデータを元に、2つ目のAPIが叩かれるはずや!」

娘「ありがとう!」

プロミスくん「おっ、最初のAPIからデータが無事に取得できたようやで!」

娘「あ、ちゃんと2つ目の処理も実行されてる!」

プロミスくん「よかったな!」

娘「うん!でも・・・」
娘「なんで関数を2個も書かないといけないの?」
娘「プロミスくんを生成する時に渡す関数と」
娘「then()に渡す関数」

プロミスくん「いや、むしろ2つに分けるから」
プロミスくん「コールバック地獄にならへんねん」

娘「あ、そっか」
娘「1つの関数の中にネストして書くと地獄になっちゃうけど」
娘「プロミスくんがresolve()経由で値をうまいこと渡してくれるから」
娘「then()に渡す関数のところで続きの処理を書けるんだね」

プロミスくん「そういうことや!」

妄想終了

娘「・・・こんな感じだね」

よめ太郎「せやな」
よめ太郎「実際の場面としては・・・」

「やめ太郎のフォロワーさん一覧をAPIから取得や!」
「次は、そのフォロワーさん達が他に誰をフォローしているかAPIから取得や!」
「その情報を元に、また別のAPIを叩く!」

よめ太郎「・・・なんて処理をする時は、Promiseを使うと書きやすくなるかもな」

処理が失敗したときのことも書ける

よめ太郎「非同期処理は失敗することもあるから・・・」

プロミスくん「なんかエラーが出て失敗した場合にはどうすればいい?」
プロミスくん「エラーが起きた場合にやって欲しい処理があったら」
プロミスくん「その内容を関数にして、ワイのcatch()メソッドに渡してや!」

よめ太郎「なんてこともしてくれるんやで」

娘「なんかthen()に似てるね」

よめ太郎「そうそう」
よめ太郎「失敗した場合のthen()みたいなもんや」

娘「そっか、APIからのデータ取得処理なんかは」
娘「必ず成功するわけじゃないもんね」

よめ太郎「せやせや」
よめ太郎「あの有名なaxios1get()メソッドなんかも」
よめ太郎「戻り値はpromiseオブジェクトやで」
よめ太郎「だから・・・」

JavaScript
axios.get('http://api.example.com/user/1')
  .then(response => nextFunc(response))
  .catch(error => console.log(error));

よめ太郎「↑こんな風に書けるんや」

娘「なるほどね〜」

よめ太郎「まだまだ奥が深いから」
よめ太郎「よかったら下の方に書いてある参考文献も読んでみてな!」

娘「うん!」

そういえばasync/awaitは?

娘「ママ、そういえば」
娘「async/awaitはどんな感じなの?」

よめ太郎「長くなり過ぎたから、次回説明するわ」

娘「その記事はいつ公開?」

よめ太郎「公開タイミングは分からん」
よめ太郎「非同期だけにな」

〜つづく〜

まとめ

  • 入れ子になりそうなコールバック処理も、
    Promiseを使ったら割と平坦に書けた。

参考文献

  1. Promiseを使う - JavaScript | MDN
  2. Promise - MDN - Mozilla
  3. Promise.prototype.then() - MDN - Mozilla
  4. Promise() コンストラクター - JavaScript | MDN

  1. 外部APIからデータを取得する為のライブラリ。 

yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。東京(三軒茶屋)/京都(四条烏丸)/札幌/大阪/福岡に展開中!Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした