5
5

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 5 years have passed since last update.

Promiseのメモ - その1: resolveとthen

Last updated at Posted at 2019-10-05

いくらPromiseの解説を読んでもよく分からないので、自分で試しながら考えます。

実行のタイミング

Promiseオブジェクトを作って返す関数で実験します。解説記事の多くは、new Promiseに渡す関数(executor)でsetTimeoutを使っていますが、ここでは使わないのがキモです。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      reject('NG');
    console.log('resolve or reject called');
  });
}

makePromise(2)としてresolve('OK')を試します。

makePromise(2).then((x) => {
  console.log(`then callback: ${x}`);
}).catch((r) => {
  console.log(`catch callback: ${r}`);
});
console.log('then and catch called');
結果
resolve or reject called
then and catch called
then callback: OK

executorは即座に実行されます。setTimeoutを使わなくてもthenに渡した関数は遅れて実行されることがわかります。

makePromise(1)としてreject('NG')を試しても同様です。catchに渡した関数は遅れて実行されます。

結果
resolve or reject called
then and catch called
catch callback: NG

executorは即座に実行され、thenやcatchに渡した関数は非同期で実行されます。executor内で呼び出すresolveとrejectは、thenやcatchに渡す関数とは別物ということです。ここがわかりにくい。

resolveとthenは何をしているのか

resolveとthenのどちらを先に実行しても、thenに渡した関数は実行されます。上記の例は、resolveのほうが先に呼ばれています。次の例は、setTimeoutを使ってthenのあとでresolveを呼びます。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(num % 2 == 0)
        resolve('OK');
      else
        reject('NG');
      console.log('resolve or reject called');
    }, 2000);
  });
}
結果
then and catch called
resolve or reject called
then callback: OK

Promiseの仕組みは次のようになっていると思われます。なお、「履行」「棄却」はfulfilled / rejectedの訳です。

  • executor内でresolveを呼び出すと、Promiseオブジェクトのステータスが「保留中」から「履行済み」となり、「履行済み結果の値」にresolveの引数(上の例では"OK")がセットされる。resolveはステータスを変えるもので、thenの関数を実行するわけではない。
  • thenに関数を渡すと、履行済みのときに実行されるコールバック関数として登録される。thenは関数を登録するもので、実行するわけではない。
  • コールバック関数を実行するのは、JavaScriptの実行環境。JavaScriptは定期的にPromiseオブジェクト一覧をチェックし、履行済みのものにコールバック関数が登録されていれば実行する。コールバック関数の引数は、resolveに渡した「履行済み結果の値」となる。

上記の説明は、resolveをreject、「履行済み」を「棄却済み」、thenをcatchとしてもたぶんだいたい同じ。

そのほかに

executor内でresolveやrejectは何度でも呼べますが、効果があるのは最初の一回だけです。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0) {
      resolve('OK1');
      resolve('OK2');
    }
    else
      reject('NG');
    console.log('resolve or reject called');
  });
}
結果
resolve or reject called
then and catch called
then callback: OK1

executor内でresolveもrejectも呼ばないと、Promiseオブジェクトはずっと保留中になります。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    console.log('do nothing');
  });
}
結果
do nothing
then and catch called

続く。

参考文献

5
5
0

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?