LoginSignup
625
630

More than 3 years have passed since last update.

私が async/await、promise をちゃんと理解するまでのステップ1,2,3

Last updated at Posted at 2019-04-27

これは何?

  • javascript の async/await を使いこなすために必要な事柄について、私なりに説明したものです。

書いてあること

  • ステップ1)await 使えば待ってくれる

    • 必要最小限の async/await、及び、エラーの catch の話
  • ステップ2)promise というもの

    • promise の中には「正常データ = resolve」と「エラー = reject」のいずれかを保管できるという話
    • どうすれば、promise から、正常データ(resolve)を取り出せるか?
    • どうすれば、promise から、エラー(reject)を取り出せるか?
    • Promise.all の話
  • ステップ3)promiseを作る方法

    • callbackスタイルの関数を、promiseスタイルとして使う方法
    • setTimeout() を promiseスタイルにする
    • async で promise を作ってみる
  • あと、参考にしたURLと、検証の為に作ったサンプルソースを付けてます。

ステップ1)await 使えば待ってくれる

  • http://.../get1 を取得した後、http://.../get2 を取得する。
  • つまり、1つ1つの処理を待ちます。(同時に動いたりしません)
async function xxx() {

  // このgetでデータ取得が完了するまで待ってから・・・
  const res1 = await axios.get('http://.../get1');
  console.log(res1);

  // 次のgetを開始する。
  const res2 = await axios.get('http://.../get2');
  console.log(res2);
}
  • もしも、await を書かなかったら、一瞬でこの関数の処理は終わってしまい console.log の出力は res1=Promise res2=Promise になってしまいます。(Promise の説明はステップ2を参照ください)
    • つまり、値が Promise になってしまったときは、await のつけ忘れを疑えばいい。
  • await を使ったときは、関数名に async というおまじないが必要なので注意
    • うっかり忘れると、async が無いと怒られます。素直に async を付けましょう。
    • 実は async の本当の意味は、「この関数は、promise を返しますよ」という宣言なのですが、ひとまず*おまじない*と理解しておいて構わないです。

少し昔 (async/await が無かった時)は、then を使ってた

  • 同じ処理を async/await を使わずに書いてみます。
function xxx() {
  axios.get('http://.../get1')
    .then((res1) => {
      // get1のデータが取得できたら、ここの処理開始
      console.log(res1);
      return(axios.get('http://.../get2'));
    })
    .then((res2) => {
      // get2のデータが取得できたら、ここの処理開始
      console.log(res2);
    });
}
  • async/await の記述の方が簡単ですね。

  • 余談ですが、、、

    • もっと昔は、callbackスタイルで非同期処理を行ってました。
    • 今現在も、fs.read() などの多くの標準関数が、callbackスタイルです。
    • 後で書きますが、callbackスタイルの関数も、簡単にpromiseスタイルに変換できるので、await も使えます。

async/await で エラーを扱う方法は?

  • 正常処理は良いとして、エラーはどのように扱えばいいんでしょうか。
  • ここでは「getでエラー発生したとき、処理を中断して関数を抜ける」方法を考えます。

try/catch でエラーをとらえる

  • async/await を使っていても、特別な書き方にはなりません。
  • 普通に try/catch が使えます。
async function xxx() {
  let res1;
  let res2;
  try {
    res1 = await axios.get('http://.../get1');
    res2 = await axios.get('http://.../get2');
  } catch(err) {
    console.log('get1 or get2 error'); //・・・どちらか一方でもエラー発生した場合
    return;
  }
  console.log(res1);
  console.log(res2);
}
  • もしも、get1、get2 で別々にエラーをとらえたいなら、それぞれに try/catch を書けばいいでしょう。

ステップ2)promise というもの

  • 実は、axios.get(url) は promise を返してきます。
  • 「え?急に何のこと言ってるの?」と思った人へ
    • 実は「axios.get(url) は取得したデータが返ってきません
    • promise というモノが返ってくるんです。
    • あとで詳しく書きますが、例えば「頭に await を付けて await axios.get(url) とすると、取得したデータが返ってきます」
  • promise の中には、「正常データ」と「エラー」のどちらかを保管できるようになっています。
    • promise流に言うと「正常データ」は「resolve」、「エラー」は「reject」と呼びます。
  • 余談ですが、、、
    • ところで 「既に、returnで正常データを、throwでエラーを返すという仕組みがあるにもかかわらず、なぜ、promiseにわざわざ、正常データとエラーを詰め込まなければならないのでしょうか?」
    • promiseは、非同期処理の結果(正常データ、エラー)を、javascriptの言語仕様として、どう扱うか決めたものです。その成果として、さらに簡単に非同期を扱えるようになった、async/awaitの存在があります。
    • つまり、promise ができたから、さらに進化して async/await が誕生したんです。
    • 5/1追記。さらに興味のある方は、コメント欄の yuta0801 さんの書き込みや、「非同期処理 · JavaScriptの入門書 #jsprimer」 を読むと、より理解が深まると思います。

どうすれば、promise から、正常データ(resolve)を取り出せるか?

  • 2つ方法があります。
  • 方法1)await をつける。
    • 例えば ret = await axios.get(url) と書けば、正常データ(ret)が取り出せます。
  • 方法2)promise の then メソッドを使う。
    • 例えば axios.get(url).then(ret => { <retを使った処理> }) と書けば、正常データ(ret)が取り出せます。

どうすれば、promise から、エラー(reject)を取り出せるか?

  • 2つ方法があります。
  • 方法1)普通に try/catch を使う。
    • try { <promiseから正常データを取り出す処理> } catch(err) { <エラー処理> }
  • 方法2)promise の .catch メソッドを使う。
    • <promiseから正常データを取り出す処理>.catch(err => { <エラー処理> })

例)await で正常データを取得して、try/catch でエラーを取り出す

  • 先の「try/catch でエラーをとらえる」に書いた通りです。

例)await で正常データを取得して、promise の .catch でエラーを取り出す

  • 回りくどいですが、まずは、私が最初にこの方法で書いたときの 間違ったコード を載せておきます。
  • といっても、promiseの使い方とかそういう次元ではなく、javascript そのものの理解度が足りずに間違って書いてしまったので、恥ずかしいミスなのですが。
async function xxx() {
  const res1 = await axios.get('http://.../get1')
    .catch((err) => {
      console.log('get1 error');
      return; // ・・・エラーだったら中断して関数を抜ける為のreturnの*つもり*だが、
    });
  console.log(res1); // ・・・実はこれ以降も実行される。res1=undefined になる。

  const res2 = await axios.get('http://.../get2');
    .catch((err) => {
      console.log('get1 error');
      return; // ・・・エラーだったら中断して関数を抜ける為のreturnの*つもり*
    });
  console.log(res2); // ・・・実はこれ以降も実行される。res2=undefined になる。
}
  • エラー発生を catch で受けて、xxx関数を抜ける為にreturnしたつもり ですが、この記述では 無名関数を抜けるだけで、xxx関数は抜けられません。
    • 代替え案としては、throw new Error('error') を使えば、一気にxxx関数を抜けられます。

そもそも、非同期で動くことが出来る axios.get を処理を待って順次実行(同期実行)するのは、もったいないのでは?

  • ということで、複数の axios.get を同時に実行(非同期実行)して、全部の処理が完了するまで待ってみます。
    • 例えば、1つの axios.get に1秒かかるとして、3つ実行した場合、、、
      • 同期実行:「axios.getを待つ → axios.getを待つ → axios.getを待つ」ので、計3秒かかります。
      • 非同期実行:「axios.getx3を同時に実行 → 全部終わるのを待つ」ので、計1秒で済みます。
async function xxx() {
  let res1;
  let res2;
  let res3;
  try {
    [res1, res2, res3] = await Promise.all([
      axios.get('http://.../get1').catch(e => { throw 'get1 error '+e.message}),
      axios.get('http://.../get2').catch(e => { throw 'get2 error '+e.message}),
      axios.get('http://.../get3').catch(e => { throw 'get3 error '+e.message}),
    ]);
  } catch(err) {
    console.log(err);
    return; // 1つでもエラーになったら、関数を抜ける
  }

  // 3つ全てが正常データを取得できたとき、以下を実行
  console.log(res1);
  console.log(res2);
  console.log(res3);
}
  • Promise.all を使うことで、3つの axios.get を同時に実行開始し、3つとも完了するのを待つことが出来ます。
  • この例では、各 axios.get に catch を付けることで、どちらのエラーが発生したか判別できるように、エラーを書き換えています。
    • しかしながら、単に、エラー検出するだけなら、外側の try/catch だけで十分です。

ステップ3)promiseを作る方法

callbackスタイル を promiseスタイルにする

  • promise が発明される以前、非同期と言えば callbackスタイル が一般的でした。
  • これらの関数を promise 化してみます。
const readFileAsync = util.promisify(fs.readFile);
text = await readFileAsync(path);
  • util.promisify を使うと、promiseスタイルの関数を得られます。
    • 他にも bluebird などでも提供されています。

setTimeout() を promiseスタイルにする

例)msec後に、正常データ('ok')を返す promise

function sleep_ok(msec) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('>>> sleep_ok() ---> resolve(ok)');
      resolve('ok');
    }, msec);
  });
}

例)msec後に、エラー(new Error('ng'))を返す promise

function sleep_ng(msec) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('>>> sleep_ng() ---> reject(new Error(ng))');
      reject(new Error('ng'));
    }, msec);
  });
}

async で promise を作ってみる

  • 「async は promise を返す」ということは、「async で promise を作れる」ということです。

「async の return」は「promise の resolve」と等価

async function async_ok() {
  console.log('>>> async_ok() ---> return(ok)');
  return 'ok'; // promise の resolve と等価
}

「async の throw」は「promise の reject」と等価

async function async_ng() {
  console.log('>>> async_ng() ---> throw new Error(ng)');
  throw new Error('ng'); // promise の reject と等価
}

参照したURL

参考)サンプルソース

  • ここまでの説明の為に作ったサンプルソースです。
  • node.js v10.15.3 を使いました。

run.sh

run.sh
set -x

:
: --------------------------------
: async/await の例
: --------------------------------
node --experimental-modules promise.mjs sample11
node --experimental-modules promise.mjs sample12
node --experimental-modules promise.mjs sample13
node --experimental-modules promise.mjs sample14
node --experimental-modules promise.mjs sample15

:
: --------------------------------
: promise の then/catch の例
: --------------------------------
node --experimental-modules promise.mjs sample21
node --experimental-modules promise.mjs sample24
node --experimental-modules promise.mjs sample25

:
: --------------------------------
: promise の resolve/reject は
: async の return/throw と等価である
: --------------------------------
node --experimental-modules promise.mjs sample31
node --experimental-modules promise.mjs sample32

:
: --------------------------------
: Promise.all の例
: --------------------------------
node --experimental-modules promise.mjs sample41
node --experimental-modules promise.mjs sample42
node --experimental-modules promise.mjs sample43
node --experimental-modules promise.mjs sample44
node --experimental-modules promise.mjs sample45

myutil.mjs

myutil.mjs
export function log(...msg) {
  const dt = new Date();
  const ms = dt.getMinutes() + ':' + dt.getSeconds();
  console.log(ms, ...msg);
}

export function sleep_ok(msec) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      log('>>> sleep_ok() ---> resolve(ok)');
      resolve('ok');
    }, msec);
  });
}

export function sleep_ng(msec) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      log('>>> sleep_ng() ---> reject(new Error(ng))');
      reject(new Error('ng'));
    }, msec);
  });
}

// msec後、consoleにlogmsgを出力して、`resolve(ret)` する。
// ただし、retがErrorのとき、`rejecti(ret)` する。
export function sleep(msec, logmsg, ret) {
  log('>>> sleep() ' + logmsg + ' in.');
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (ret instanceof Error) {
        log('>>> sleep() ' + logmsg + ' out reject()');
        reject(ret);  // Error のとき reject
      } else {
        log('>>> sleep() ' + logmsg + ' out resolve()');
        resolve(ret);
      }
    }, msec);
  });
}

promise.mjs

promise.mjs
import {log, sleep_ok, sleep_ng} from './myutil.mjs'

async function sample11() {
  console.log('// await で待つ');
  log('-- 1');
  log(await sleep_ok(1000));
  log('-- 2');
  log(await sleep_ok(1000));
  log('-- 3');
}

function sample12() {
  console.log('// もしも、await をつけなかったら?');
  log('-- 1');
  log(sleep_ok(1000));
  log('-- 2');
  log(sleep_ok(1000));
  log('-- 3');
}

async function sample13() {
  console.log('// エラーだったら?(rejectされたら?)');
  log('-- 1');
  log(await sleep_ok(1000));
  log('-- 2');
  log(await sleep_ng(1000));
  log('-- ここには到達しない');
}

async function sample14() {
  console.log('// エラーをtry/catchしてみる');
  log('-- 1');
  log(await sleep_ok(1000));
  log('-- 2');
  try {
    log(await sleep_ng(1000));
  } catch (e) {
    log('-- 3 try/catch() e.message=' + e.message);
  }
  log('-- 4');
}

async function sample15() {
  console.log('// エラー発生で即関数を抜ける');
  try {
    log('-- 1');
    log(await sleep_ok(1000));
    log('-- 2');
    log(await sleep_ng(1000));
    log('-- ここには到達しない');
  } catch (e) {
    log('-- 3 try/catch() e.message=' + e.message);
    log('-- 4 return');
    return;
  }
  log('-- ここには到達しない');
}

function sample21() {
  console.log('// sample11 を promiseのthen で記述してみる');
  log('-- 1');
  sleep_ok(1000)
    .then((ret) => {
      log(ret);
      log('-- 3');
      return(sleep_ok(1000));
    })
    .then((ret) => {
      log(ret);
      log('-- 4');
    });
  log('-- 2 これが2になる。4の次にはならないので注意');
}

function sample24() {
  console.log('// sample14 を promiseのthen/catch で記述してみる');
  log('-- 1');
  sleep_ok(1000)
    .then((ret) => {
      log(ret);
      log('-- 3');
      return(sleep_ng(1000));
    })
    .then((ret) => {
      log(ret);
      log('-- ここには到達しない');
    })
    .catch((err) => {
      log('--4 catch() err.message=' + err.message);
    });
  log('-- 2 これが2になる。4の次にはならないので注意');
}

function sample25() {
  console.log('// sample15 を promiseのthen/catch で記述してみる');
  log('-- 1');
  sleep_ok(1000)
    .then((ret) => {
      log(ret);
      log('-- 3');
      return(sleep_ng(1000));
    })
    .then((ret) => {
      log(ret);
      log('-- ここには到達しない');
    })
    .catch((err) => {
      log('--4 catch() err.message=' + err.message);
      log('--5 ここにreturnと書いても、親関数を抜ける意味にはならないので注意');
      return;
    });
  log('-- 2 ついつい「5でreturnしているので、ここには到達しない」と考えてしまうが、そうはならないので注意');
}

async function async_ok() {
  log('>>> async_ok() ---> return(ok)');
  return 'ok'; // promise の resolve と等価
}

async function async_ng() {
  log('>>> async_ng() ---> throw new Error(ng)');
  throw new Error('ng'); // promise の reject と等価
}

async function sample31() {
  console.log('// 「promise の resolve」は「async の return」と等価');
  log('-- 1');
  log(await async_ok());
  log('-- 2');
  log(await sleep_ok(0));
  log('-- 3');
}

async function sample32() {
  console.log('// 「promise の reject」は「async の throw」と等価');
  log('-- 1');
  try {
    await async_ng();
  } catch(err) {
    log('-- 2 catch() err.message=' + err.message);
  }
  log('-- 3');
  try {
    await sleep_ng(0);
  } catch(err) {
    log('-- 4 catch() err.message=' + err.message);
  }
  log('-- 5');
}

async function sample41() {
  console.log('// Promise.all で待つ');
  log('-- 1');
  let ret = await Promise.all([
    sleep_ok(1000),
    sleep_ok(2000)
  ]);
  log(ret);
  log('-- 2');
}

async function sample42() {
  console.log('// Promise.all で、ngがあるとき');
  log('-- 1');
  let ret = await Promise.all([
    sleep_ok(1000),
    sleep_ng(2000)
  ]);
  log('-- ここには到達しない');
  log(ret);
}

async function sample43() {
  console.log('// Promise.all で try/catch');
  log('-- 1');
  let ret;
  try {
    ret = await Promise.all([
      sleep_ok(1000),
      sleep_ng(2000)
    ]);
  } catch(err) { // どちらの処理のエラーかはわからない。(errの戻り値を工夫する必要あり)
    log('-- 2 catch() err.message=' + err.message);
    return; // ここで処理抜ける
  }
  log('-- ここには到達しない');
  log(ret);
}

async function sample44() {
  console.log('// Promise.all の try/catch で promise を直接見れば、どれのエラーか判別できる?');
  log('-- 1');
  let p = Promise.all([
    sleep_ok(1000),
    sleep_ng(2000)
  ]);
  let ret;
  try {
    ret = await p;
  } catch(err) {
    log('-- 2 catch() err.message=' + err.message);
    log('p=', p); // 判別できない
    return; // ここで処理抜ける
  }
  log('-- ここには到達しない');
  log(ret);
}

async function sample45() {
  console.log('// 個々のpromiseにcatchをつけ、ユニークなthrowとすることで誰がエラーになったか判別する');
  log('-- 1');
  let ret;
  try {
    ret = await Promise.all([
      sleep_ok(1000).catch(err => { throw new Error('sleep_ok(1000)') }),
      sleep_ng(2000).catch(err => { throw new Error('sleep_ng(2000)') })
    ]);
  } catch(err) {
    log('-- 2 catch() err.message=' + err.message);
    return; // ここで処理抜ける
  }
  log('-- ここには到達しない');
  log(ret);
}


const funcname = process.argv[2] + '()';
console.log('');
console.log('### ' + funcname);
eval(funcname);

実行結果

ubuntu@ubuntu201809:~/20190427node$ ./run.sh |& cat -n
     1  ++ :
     2  ++ : --------------------------------
     3  ++ : async/await の例
     4  ++ : --------------------------------
     5  ++ node --experimental-modules promise.mjs sample11
     6  (node:11925) ExperimentalWarning: The ESM module loader is experimental.
     7  
     8  ### sample11()
     9  // await で待つ
    10  5:23 -- 1
    11  5:24 >>> sleep_ok() ---> resolve(ok)
    12  5:24 ok
    13  5:24 -- 2
    14  5:25 >>> sleep_ok() ---> resolve(ok)
    15  5:25 ok
    16  5:25 -- 3
    17  ++ node --experimental-modules promise.mjs sample12
    18  (node:11936) ExperimentalWarning: The ESM module loader is experimental.
    19  
    20  ### sample12()
    21  // もしも、await をつけなかったら?
    22  5:25 -- 1
    23  5:25 Promise { <pending> }
    24  5:25 -- 2
    25  5:25 Promise { <pending> }
    26  5:25 -- 3
    27  5:26 >>> sleep_ok() ---> resolve(ok)
    28  5:26 >>> sleep_ok() ---> resolve(ok)
    29  ++ node --experimental-modules promise.mjs sample13
    30  (node:11947) ExperimentalWarning: The ESM module loader is experimental.
    31  
    32  ### sample13()
    33  // エラーだったら?(rejectされたら?)
    34  5:27 -- 1
    35  5:28 >>> sleep_ok() ---> resolve(ok)
    36  5:28 ok
    37  5:28 -- 2
    38  5:29 >>> sleep_ng() ---> reject(new Error(ng))
    39  (node:11947) UnhandledPromiseRejectionWarning: Error: ng
    40      at Timeout.setTimeout [as _onTimeout] (file:///home/ubuntu/20190427node/myutil.mjs:20:14)
    41      at ontimeout (timers.js:436:11)
    42      at tryOnTimeout (timers.js:300:5)
    43      at listOnTimeout (timers.js:263:5)
    44      at Timer.processTimers (timers.js:223:10)
    45  (node:11947) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    46  (node:11947) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    47  ++ node --experimental-modules promise.mjs sample14
    48  (node:11958) ExperimentalWarning: The ESM module loader is experimental.
    49  
    50  ### sample14()
    51  // エラーをtry/catchしてみる
    52  5:29 -- 1
    53  5:30 >>> sleep_ok() ---> resolve(ok)
    54  5:30 ok
    55  5:30 -- 2
    56  5:31 >>> sleep_ng() ---> reject(new Error(ng))
    57  5:31 -- 3 try/catch() e.message=ng
    58  5:31 -- 4
    59  ++ node --experimental-modules promise.mjs sample15
    60  (node:11969) ExperimentalWarning: The ESM module loader is experimental.
    61  
    62  ### sample15()
    63  // エラー発生で即関数を抜ける
    64  5:31 -- 1
    65  5:32 >>> sleep_ok() ---> resolve(ok)
    66  5:32 ok
    67  5:32 -- 2
    68  5:33 >>> sleep_ng() ---> reject(new Error(ng))
    69  5:33 -- 3 try/catch() e.message=ng
    70  5:33 -- 4 return
    71  ++ :
    72  ++ : --------------------------------
    73  ++ : promise の then/catch の例
    74  ++ : --------------------------------
    75  ++ node --experimental-modules promise.mjs sample21
    76  (node:11980) ExperimentalWarning: The ESM module loader is experimental.
    77  
    78  ### sample21()
    79  // sample11 を promiseのthen で記述してみる
    80  5:33 -- 1
    81  5:33 -- 2 これが2になる。4の次にはならないので注意
    82  5:34 >>> sleep_ok() ---> resolve(ok)
    83  5:34 ok
    84  5:34 -- 3
    85  5:35 >>> sleep_ok() ---> resolve(ok)
    86  5:35 ok
    87  5:35 -- 4
    88  ++ node --experimental-modules promise.mjs sample24
    89  (node:11991) ExperimentalWarning: The ESM module loader is experimental.
    90  
    91  ### sample24()
    92  // sample14 を promiseのthen/catch で記述してみる
    93  5:35 -- 1
    94  5:35 -- 2 これが2になる。4の次にはならないので注意
    95  5:36 >>> sleep_ok() ---> resolve(ok)
    96  5:36 ok
    97  5:36 -- 3
    98  5:37 >>> sleep_ng() ---> reject(new Error(ng))
    99  5:37 --4 catch() err.message=ng
   100  ++ node --experimental-modules promise.mjs sample25
   101  (node:12002) ExperimentalWarning: The ESM module loader is experimental.
   102  
   103  ### sample25()
   104  // sample15 を promiseのthen/catch で記述してみる
   105  5:37 -- 1
   106  5:37 -- 2 ついつい「5でreturnしているので、ここには到達しない」と考えてしまうが、そうはならないので注意
   107  5:38 >>> sleep_ok() ---> resolve(ok)
   108  5:38 ok
   109  5:38 -- 3
   110  5:39 >>> sleep_ng() ---> reject(new Error(ng))
   111  5:39 --4 catch() err.message=ng
   112  5:39 --5 ここにreturnと書いても、親関数を抜ける意味にはならないので注意
   113  ++ :
   114  ++ : --------------------------------
   115  ++ : promise の resolve/reject は
   116  ++ : async の return/throw と等価である
   117  ++ : --------------------------------
   118  ++ node --experimental-modules promise.mjs sample31
   119  (node:12013) ExperimentalWarning: The ESM module loader is experimental.
   120  
   121  ### sample31()
   122  // 「promise の resolve」は「async の return」と等価
   123  5:39 -- 1
   124  5:39 >>> async_ok() ---> return(ok)
   125  5:39 ok
   126  5:39 -- 2
   127  5:39 >>> sleep_ok() ---> resolve(ok)
   128  5:39 ok
   129  5:39 -- 3
   130  ++ node --experimental-modules promise.mjs sample32
   131  (node:12024) ExperimentalWarning: The ESM module loader is experimental.
   132  
   133  ### sample32()
   134  // 「promise の reject」は「async の throw」と等価
   135  5:40 -- 1
   136  5:40 >>> async_ng() ---> throw new Error(ng)
   137  5:40 -- 2 catch() err.message=ng
   138  5:40 -- 3
   139  5:40 >>> sleep_ng() ---> reject(new Error(ng))
   140  5:40 -- 4 catch() err.message=ng
   141  5:40 -- 5
   142  ++ :
   143  ++ : --------------------------------
   144  ++ : Promise.all の例
   145  ++ : --------------------------------
   146  ++ node --experimental-modules promise.mjs sample41
   147  (node:12035) ExperimentalWarning: The ESM module loader is experimental.
   148  
   149  ### sample41()
   150  // Promise.all で待つ
   151  5:40 -- 1
   152  5:41 >>> sleep_ok() ---> resolve(ok)
   153  5:42 >>> sleep_ok() ---> resolve(ok)
   154  5:42 [ 'ok', 'ok' ]
   155  5:42 -- 2
   156  ++ node --experimental-modules promise.mjs sample42
   157  (node:12046) ExperimentalWarning: The ESM module loader is experimental.
   158  
   159  ### sample42()
   160  // Promise.all で、ngがあるとき
   161  5:42 -- 1
   162  5:43 >>> sleep_ok() ---> resolve(ok)
   163  5:44 >>> sleep_ng() ---> reject(new Error(ng))
   164  (node:12046) UnhandledPromiseRejectionWarning: Error: ng
   165      at Timeout.setTimeout [as _onTimeout] (file:///home/ubuntu/20190427node/myutil.mjs:20:14)
   166      at ontimeout (timers.js:436:11)
   167      at tryOnTimeout (timers.js:300:5)
   168      at listOnTimeout (timers.js:263:5)
   169      at Timer.processTimers (timers.js:223:10)
   170  (node:12046) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
   171  (node:12046) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
   172  ++ node --experimental-modules promise.mjs sample43
   173  (node:12057) ExperimentalWarning: The ESM module loader is experimental.
   174  
   175  ### sample43()
   176  // Promise.all で try/catch
   177  5:44 -- 1
   178  5:45 >>> sleep_ok() ---> resolve(ok)
   179  5:46 >>> sleep_ng() ---> reject(new Error(ng))
   180  5:46 -- 2 catch() err.message=ng
   181  ++ node --experimental-modules promise.mjs sample44
   182  (node:12069) ExperimentalWarning: The ESM module loader is experimental.
   183  
   184  ### sample44()
   185  // Promise.all の try/catch で promise を直接見れば、どれのエラーか判別できる?
   186  5:46 -- 1
   187  5:47 >>> sleep_ok() ---> resolve(ok)
   188  5:48 >>> sleep_ng() ---> reject(new Error(ng))
   189  5:48 -- 2 catch() err.message=ng
   190  5:48 p= Promise {
   191    <rejected> Error: ng
   192        at Timeout.setTimeout [as _onTimeout] (file:///home/ubuntu/20190427node/myutil.mjs:20:14)
   193        at ontimeout (timers.js:436:11)
   194        at tryOnTimeout (timers.js:300:5)
   195        at listOnTimeout (timers.js:263:5)
   196        at Timer.processTimers (timers.js:223:10) }
   197  ++ node --experimental-modules promise.mjs sample45
   198  (node:12080) ExperimentalWarning: The ESM module loader is experimental.
   199  
   200  ### sample45()
   201  // 個々のpromiseにcatchをつけ、ユニークなthrowとすることで誰がエラーになったか判別する
   202  5:48 -- 1
   203  5:49 >>> sleep_ok() ---> resolve(ok)
   204  5:50 >>> sleep_ng() ---> reject(new Error(ng))
   205  5:50 -- 2 catch() err.message=sleep_ng(2000)
ubuntu@ubuntu201809:~/20190427node$ 
625
630
6

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
625
630