Edited at

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


これは何?


  • 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$