LoginSignup
8
9

非同期処理と同期処理の違い(Promiseの例)

Last updated at Posted at 2023-08-26

モチベーション

「複数の仕事をする際に、反応を待たないで次の処理を実行する」という概念を現実的なシナリオに当てはめてみます。あなたのライフスタイルを通じて、非同期処理の考え方を理解しましょう。

非同期のライフスタイル

あなたは趣味でトマトをプランターで栽培しています。最初に、トマトの種をプランターの土に埋めました。トマトの成熟するまでの時間は分からないものの、実ったら美味しいカプレーゼを楽しもうと妄想します。その後、あなたはいつも通りの生活を過ごします。

あなたはプログラマーで、いつも家の窓際でPC作業をしています。時々窓の外に目を移して、プランターの様子を伺います。

2か月後、ついにその日がやってきました。赤いトマトが実ったのです!計画通り、トマトでカプレーゼを作ることにしました。トマトをスライスし、モッツァレラチーズと交互に並べ、オリーブオイルを完成!そして、辛口の白ワインと舌鼓、ああ、至福の時間…。

解説

この場合、あなたの振る舞いは非同期的です!あなたはトマト栽培とプログラミングのタスクを抱えていますが、トマトの成熟する間に他の作業もこなしています。もしいつ成熟するか分からないのにプランターの前で座していれば、プログラミングの仕事も進まないでしょう。実に賢明です。

そして、トマトが実ったら、待ってましたとばかりにカプレーゼに仕立て上げた手際も見事です!前々から調理するところを妄想していましたからね。

このように、トマトの成熟を待つ間に他の作業をこなし、成果を最大にする姿勢は非同期処理のイメージそのものです。

Promiseの例

このシナリオをTypeScriptで表現すると以下のようになります。

function live() {
  const tomatoEnjoy = new Promise<string>((resolve) => {
    // トマトが成熟する、これは時間がかかる処理
    // resolve(トマト);
  });

  tomatoEnjoy.then((トマト) => {
    // トマトをスライスする
    // トマトとチーズを交互に並べる
    // オリーブオイルをかける
    // 白ワインと一緒に楽しむ
  }).catch((error) => {
    // トマトが枯れてしまった…
  });

  // ここで、プログラミングの仕事を繰り返す
}

live();

Promiseを使った場合、then()の中でPromise完遂した時(トマトが実った後)にどうするかを記述することになります。また、catch()の中でPromise失敗した時(トマトが枯れた後)にどうするかを記述できます。

同期のライフスタイル(?)

もしくは、あなたはプランターの前でトマトが実るのを待つかもしれません。実る時期も、実るかどうかすら分かりません。それでもカプレーゼが楽しみで仕方がないのです!

Promiseの例

プログラマーの仕事(それだけでなく、食事や睡眠も!)をカプレーゼの後に行うことを選ぶなら、トマトの成熟をawaitしましょう。

async function live() {
  const tomatoEnjoy = new Promise<string>((resolve) => {
    // トマトができる、時間がかかる処理
    // resolve(トマト);
  });

  await tomatoEnjoy.then((トマト) => {
    // スライスする
    // チーズと交互に並べる
    // オリーブオイルをかける
    // 白ワインと一緒に楽しむ
  }).catch((error) => {
    // トマトが枯れてしまった…
  });

  // ここで、プログラミングの仕事を処理を繰り返す
}

live();

ここで、live()メソッドにも async キーワードが付加されていることに注目してください。awaitを使用する際には、それを含むメソッドをasyncに変更する必要があります。つまり、live()メソッド全体を非同期にします。

解説

こんなふうに考えるかもしれません。「トマト栽培とプログラミングを順番=同期的に行ったのに、どうして非同期なんだ!?」と。

じっくりと考えてみましょう。あなたがプログラミングの仕事に取りかかるタイミングは、いつトマトが実るかに影響されています。あなたの上司は、あなたがいつ与えたタスクを完了してくれるのか分かりません。あなたの奥さんは、あなたがいつ植木鉢とのにらめっこをやめて、家事を手伝ってくれるのか分かりません。

確かにあなたは自分の行動を同期的に進めています。しかし、あなたの周囲の人々にとって、あなたの生活は非同期的すぎるのです!おそらく、トマトが終わるのを見計らって、上司から次のタスクを、奥さんからお皿洗いの手伝いを頼まれるでしょう。

トマトを栽培しつつ、同期的に生活する(かつ、人間関係を損なわない)なんて無理な話なのです。トマトが成熟するタイミングが分からないのですから…

おまけ:動くコード

ぜひ、TypeScript Playgroundで試してみてください。

function live() {
  const tomatoEnjoy = new Promise<string>((resolve) => {
    let crop = 'tomato';
    let harvestPeriod = 5000;

    // 収穫に失敗した場合
    // throw new Error();

    // 収穫に成功した場合
    setTimeout(() => {
      resolve(crop);
    }, harvestPeriod);
  });

  // ここにawaitを加えることで、トマトの成長を待つことができる
  // その場合functionの先頭にasyncを加える
  tomatoEnjoy.then((crop: string) => {
    console.log('Cooking!');
    console.log('Enjoy ' + crop + '!');
  }).catch((error) => {
    console.log('Failure...');
    console.log(error);
  });
  
  console.log('programming life...');
}

live();

TypeScript初学者なので、解釈が間違っていることもあるかもしれません。何かお気づきの点がございましたら、ご指摘いただけると幸いです。

8
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9