これは何?
- 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秒で済みます。
- 例えば、1つの axios.get に1秒かかるとして、3つ実行した場合、、、
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
-
javascript の非同期処理について、学ぶにあたって参照させて頂いたURLです。皆さんありがとうございます。
-
コールバックスタイルの非同期処理をpromise化するモジュールの話
- util.promisify()でcallbackスタイルの関数をpromise化 - Qiita https://qiita.com/t-okushima/items/fbca67541003576997cc
-
標準のpromiseより、さらに高機能なものの話
- PromiseとQとBluebird - Qiita https://qiita.com/kamijin_fanta/items/21a061a00575f0a357c6
-
Array の map、filter で async/await を使ったときに、うまく動かすことが出来ず、参考にさせてもらいました。
- Array 操作関数の callback に async/await な関数を指定したい - Qiita https://qiita.com/janus_wel/items/1dc491d866f49af76e98
-
コンパクトにまとめられた説明です。async の正体を教えてもらいました。
- async/await 入門(JavaScript) - Qiita https://qiita.com/soarflat/items/1a9613e023200bbebcb3
-
長文ですが、とても詳しい説明です。このレベルの情報がネットで簡単に見られるのは助かります。
- 非同期処理 · JavaScriptの入門書 #jsprimer https://jsprimer.net/basic/async/
参考)サンプルソース
- ここまでの説明の為に作ったサンプルソースです。
- 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$