0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Promise嫌いを治したい。薄くまとめた本でとりあえずざっくりPromiseを復習してみた。

Last updated at Posted at 2022-12-21

はじめに

JS...。実を言うとあまり好きになれないのですよね。理由の一つはPromiseなのかなと思っています。初学者の時に無理やり詰め込んで覚えたこちら。曖昧なところもあるままasync, awaitはもちろん、TSでも扱うようにしたら、自然と避けるようになってしまい。。。良くないので、これを機に全体をざっくり復習しようと思います。

使用テキスト

今回の使用テキストはこちらです。

かの有名なJS Primerの使用も考えたのですが、丁寧に記載がされすぎていて、かえってまとめるのが難しかったので。上記のJavaScript コードレシピ集の方は、Promise~async, awaitを約20ページにまとめているので、非常に読みやすかったです!
引用したコードには基本的に引用元のページ数をつけています。

基本のPromise

thenで最初の処理に続く処理を記載できる

基本のPromiseの処理はこんな感じ。①resolve()で1つ目の処理の完了させ、②.then()で続けて処理したい内容を記載します。

const promise = new Promise((resolve) => {
  console.log("最初の処理", Date.now())

  setTimeout(() => {
    resolve(); // 最初の処理の完了
  }, 1000);
});

promise.then(() => { // then以降は最初の処理の1秒後に実行される
  console.log("次の処理", Date.now())
})

JavaScript コードレシピ集 p.471 のコードに追記して使用

「最初の処理」が実行されてから1(=1000ミリ)秒後に「次の処理」が実行されます。
Image from Gyazo

間にブロックする処理を挟んでも、thenに記載した処理は実行される

この時 「最初の処理」「次の処理」 の間に、それを 「ブロックする処理」 を挟み込みます。

const promise = new Promise((resolve) => {
  console.log("最初の処理", Date.now())
  setTimeout(() => {
    resolve();
  }, 1000);
});

// ここを追加
setTimeout(() => {
  console.log("ブロックする処理")
}, 5000);

promise.then(() => {
  console.log("次の処理", Date.now())
})

通常なら、「最初の処理」「ブロックする処理」「次の処理」 の順に処理が走りそうですが、
promiseを使っていることで
「最初の処理」「次の処理」「ブロックする処理」 の順に処理が走ります。

Image from Gyazo

Promiseで指定した処理にエラーが出たらcatchで続けることができる

Promiseの中で記載した処理に失敗した時には、catchを使って処理を続けることができます。
次のコードだと、1/2の確率でflagtrueではなくなり、「失敗時の処理」がコンソールに出力されます。

const flag = Math.random() < 0.5 && true
const promise = new Promise((resolve, reject) =>{
  if (flag === true) {
    resolve('成功時の処理');
  } else {
    reject('失敗時の処理');
  }
})

promise.then((value) => {
  console.log(value)
})

promise.catch((value) => {
  console.log(value)
})

JavaScript コードレシピ集 p.473 のコードを改変して使用

失敗時にはこのようにコンソールに表示されるのですが、どうしてエラー文まで出るのかは謎です。
Image from Gyazo

直列処理とasync, await

まずはサンプルコード

.thenでメソッドチェーン的にPromiseの処理を続けて書くことができます。

Promise.resolve()
  .then(
    () =>
      new Promise((resolve) => {
        setTimeout(() => {
          console.log('1つ目のPromise', new Date().toLocaleTimeString());
          resolve();
        }, 1000);
      })
  )
  .then(
    () =>
      new Promise((resolve) => {
        setTimeout(() => {
          console.log('2つ目のPromise', new Date().toLocaleTimeString());
          resolve();
        }, 1000);
      })
  )

JavaScript コードレシピ集 p.477 のコードを抜粋

そして、直列処理のpromiseはasync, await構文を使うとより簡潔に書けます。

async function start() {
  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('1つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000);
  })

  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('2つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000);
  })
}

start();

JavaScript コードレシピ集 p.478 のコードを抜粋

詳細確認

わーい、簡単♪ ...と思いきや、謎もやはり多いですよね。まずはこの部分。

Promise.resolve()
  .then(
    () =>
      new Promise((resolve) => { // ←引数resolveとは?
        setTimeout(() => {
          console.log('1つ目のPromise', new 
     //... 以下略

突如出てきたように見える、引数のresolveってなんやねん!?ってなりませんでしたか?(私はなりました)。
Promiseでは、直前のPromiseの成功時に返された値を、次のthenの引数として使えるそうなので、その値です。
なので、次のような直列処理の式も成立します。

Promise.resolve(1) // ここのresolveは成功時に1を返すpromiseを作る
  .then((value) => {
        console.log(value); // 1が表示される
        return value * 2
      })
  .then(
    (value) => {
      console.log(value);  // 2が表示される
      return value * 2
    })

JavaScript Primer P.277 のコードを改変して使用

そして、async, await構文についてですが、まず、

  • awaitは右辺の式が実行されるまで次の処理を待つ機能です
  • asyncpromiseインスタンスを返すメソッドです。

なので、こちらのasync構文は一つ目のPromiseを行なって、二つ目のPromiseを実行するという一連の処理の流れを持ったPromiseインスタンスを返す構文となります。

const start = async () => {
  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('1つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000); // 1. この処理が終わったら
  })

  await new Promise((resolve) => {
    setTimeout(() => {
      console.log('2つ目のPromise', new Date().toLocaleTimeString());
      resolve();
    }, 1000); // 2. この処理を実行して
  })
}

start(); // 1~2の一連の流れが詰まったメソッド

まとめ

以上となりましたが、ざっくりとPromiseの流れを復習しました。今だからわかることも多いけど、初学者の時には分かりにくかったこともあり、やはり定期的に復習は大事だなと思いました。

手元にあるTSの書籍についても非同期処理の記述があるので、引き続きTSにおけるPromiseの扱いについて復習したいと思います。

0
0
3

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?