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

Promise再入門① ~Promise基本編~

More than 3 years have passed since last update.

概要

PromiseはモダンJSでコーディングする際の肝の1つです。
Promiseを制するものが、モダンJSを制するものと言っても言い過ぎではないと思います。

ES7では、いよいよasync/awaitが実装されます。
今まで感覚で使っていた部分もあるPromiseを再度学習し直そうと思います。

Promiseとは

  • 非同期の処理を分かりやすく制御するオブジェクト
  • ES6に追加された機能の1つ
  • IE対応用のPolyfillも完備

Promiseの使い方

  • Promiseはnewして使う。
  • Promiseオブジェクトの第1引数は必ず関数
    • Promiseの第1引数の関数はは 成功時の処理失敗時の処理 を実行する引数(関数)を取得できる。
    • 成功 -> resolve(渡したい値)
    • 失敗 -> reject(渡したい値)
  • newされたPromiseは以下の関数を持つオブジェクトを返す
    • then(onFulfilled,onRejected),catch(onRejected)
    • thenでresolveされた時の処理、catchでrejectされた時の処理を受け取る
    • thenもcatchも引数を持つ関数を引数に取る
    • catchはエラーの処理が明確になるだけでなく、複数の非同期処理のエラーをまとめて制御する為にも使用される
    • 基本的には、catchを使って失敗時の処理を記述する
const promise = new Promise((resolve, reject) => {
  window.setTimeout(() => {
    resolve('OK');
  }, 2000);
});

promise
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error);
  });

Promiseパターン

Promiseを使って同期的に処理

  • thenの中でPromiseを返せば、さらにthenを続けて記載する事が可能
  • 今回の例では、同期的に処理される。
    • func1の非同期処理の完了後、func2がコールバックされて、func2の非同期が完了後、次のthenに移っている。
    • Promiseを返さなければ、並列で処理されるthenとなる
const func1 = (num) => {
  return new Promise((resolve) => {
    window.setTimeout(() => {
      resolve(num);
    }, 3000);
  });
};

const func2 = (num) => {
  return new Promise((resolve) => {
    window.setTimeout(() => {
      resolve(num * num);
    }, 2000);
  });
};

func1(2)
  .then(func2)
  .then((result) => {
    console.log(result);
  })
  .catch((e) => {
    console.log(e);
  });
  • コールバック地獄が容易に想像出来るが下記の様な書き方も可能
...

func1(2)
  .then((res1) => {
    func2(res1)
      .then((res2) => {
        console.log(res2);
      });
  });

Promiseを使って並列処理して完了を検知する

  • 複数の非同期処理を並列で実行し、全てが完了したら情報を取得する
    • 非同期のメリット
  • Promise.all([Promise, Promise...])を使って、非同期な処理を並列で行い、全てがresolveになるタイミングでthenを取得する。
  • 並列処理しているもので1つでもrejectがあれば、catchされる。
const func1 = (num) => {
  return new Promise((res) => {
    window.setTimeout(() => {
      res(num + num);
    }, 500);
  });
};

const func2 = (num) => {
  return new Promise((res, rej) => {
    window.setTimeout(() => {
      rej(num * num);
    }, 2000);
  });
};

Promise.all([
  func1(2),
  func2(3)
])
.then((results) => {
  console.log(results);
})
.catch((e) => {
  console.log(e);
});

1つでも処理が返ってきたら実行する

  • Promise.race([Promise, Promise...])を使う事で、resolveもcatchでも何かしら処理が返ってきたら次の処理(thenやcatch)を実行する様に出来る。
const func1 = (num) => {
  return new Promise((res) => {
    window.setTimeout(() => {
      res(num + num);
    }, 500);
  });
};

const func2 = (num) => {
  return new Promise((res, rej) => {
    window.setTimeout(() => {
      rej(num * num);
    }, 2000);
  });
};


Promise.race([
  func1(3),
  func2(3)
])
.then((res) => {
  console.log(res);
})
.catch((e) => {
  console.log(e);
});

終わり

今回は基本編という事で、Promiseオブジェクトの最低限の知識をまとめました。
次回は、ES7で実装されるasync/awaitを使って、より柔軟にPromiseを使って見たいと思います。

tfrcm
React / ReactNative / Go / TypeScript / AWS / Docker / k8s
https://gemcook.com
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
ユーザーは見つかりませんでした