非同期処理待ちを簡潔に書けるPromise+async/await
日付 タグ node.js カテゴリ node.js目次
Promiseのthenチェーンが長くて見づらいのを簡潔にする
この前、Promiseを利用すると非同期処理1の完了を待って、非同期処理2に進めるという順番制御ができる話を書いた。 ( ==> Node.jsで非同期処理待ちを実現するPromise )
また、thenをチェーンさせることで、多段に非同期処理待ちを繋げていくことが可能であることを、そこで確認した。
再度、その時のプログラムを見ておくと、
timer_promise_chain_test.js
function myFuncPromise(value){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(`myFuncの実行中:引数${value}`);
console.log(`${value}ms待ち完了`);
console.log('=======');
resolve('処理待ちしたよ');
}, value);
});
}
myFuncPromise(3000)
.then((value) => {
console.log(value);
console.log('=>thenに処理が来ました=>');
return myFuncPromise(2000);
})
.then((value) => {
console.log(value);
console.log('=>thenに処理が来ました=>');
return myFuncPromise(1000);
})
.then((value) => {
console.log('全部が終了');
}).catch((error) => {
console.log('エラー発生');
console.error(error);
});
そこまでひどいわけではないのだが、なんとなくthenが.で繋がっていくのが見にくいといえば、見にくい。
async/awaitを使ってthenチェーンをなくす
このthenチェーンをなくすためにasyncとawaitを使うと、より簡潔にコードがかける。
awaitは指定した関数のPromiseの結果(resolve or reject)が返されるまで、function内の処理を止める作用があるのだが、そのfunctionはasync(非同期関数)として定義されている必要がある。
つまり、async function内でawaitが出てくると、そこで指定された関数のPromiseの結果を待って、次に処理が進むということになる。
さて、この性質を利用して、thenチェーンを取り外した例を見てみる。
timer_promise_await_resolve.js
function myFuncPromise(value){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(`myFuncの実行中:引数${value}`);
console.log(`${value}ms待ち完了`);
console.log('=======');
resolve('処理待ちしたよ');
}, value);
});
}
async function sample() {
const result1 = await myFuncPromise(3000);
console.log('result1:'+result1);
const result2 = await myFuncPromise(2000);
console.log('result2:'+result1);
const result3 = await myFuncPromise(1000);
console.log('result3:'+result1);
}
sample().then((value) => {
console.log('全部が終了');
});
async/awaitを使ったことでthenチェーンはなくなった。
唯一の見えるthenは一番最後に「全部が終了」と見えるところだけ。
実行結果はこうなる。
$ node timer_promise_await_resolve.js
myFuncの実行中:引数3000
3000ms待ち完了
=======
result1:処理待ちしたよ
myFuncの実行中:引数2000
2000ms待ち完了
=======
result2:処理待ちしたよ
myFuncの実行中:引数1000
1000ms待ち完了
=======
result3:処理待ちしたよ
全部が終了
確かに3秒待ちの処理、2秒待ちの処理、1秒待ちの処理と順番に結果が表示されている。 もし、非同期処理完了待ちが出来ていなかったら、待ち時間の短いものから結果がconsoleに表示されてしまっていたであろう。
ここで戻りがresolveの場合を見ていたが、じゃあ、rejectの場合はどうなのかと見てみると、try-catchを使えば、rejectのエラーを捕捉することができる。
例を見てみる。
timer_promise_await_reject.js
function myFuncPromise(value){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(`myFuncの実行中:引数${value}`);
console.log(`${value}ms待ち完了`);
console.log('=======');
reject('失敗例');
}, value);
});
}
async function sample() {
try {
const result1 = await myFuncPromise(3000);
console.log(result1);
const result2 = await myFuncPromise(2000);
console.log(result2);
const result3 = await myFuncPromise(1000);
console.log(result3);
} catch(err) {
console.error('cathed error:' + err);
}
}
sample().then((value) => {
console.log('全部が終了');
});
これを実行すると、
$ node timer_promise_await_reject.js
myFuncの実行中:引数3000
3000ms待ち完了
=======
cathed error:失敗例
全部が終了
つまりrejectを大枠でtry - catchで囲っている場合は、最初のエラーでcatchに飛んで処理が終わるのだ。
もしも細かい単位でtry - catchするならば、より細かくエラーによる処理遷移を行うことができる。
timer_promise_await_reject.jsを少し書き換えてみる。
timer_promise_await_reject.js
function myFuncPromise(value){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(`myFuncの実行中:引数${value}`);
console.log(`${value}ms待ち完了`);
console.log('=======');
reject('失敗例');
}, value);
});
}
async function sample() {
try {
const result1 = await myFuncPromise(3000);
console.log(result1);
} catch(err) {
console.error('cathed error:' + err);
}
try {
const result2 = await myFuncPromise(2000);
console.log(result2);
} catch(err) {
console.error('cathed error:' + err);
}
try {
const result3 = await myFuncPromise(1000);
console.log(result3);
} catch(err) {
console.error('cathed error:' + err);
}
}
sample().then((value) => {
console.log('全部が終了');
});
$ node timer_promise_await_reject.js
myFuncの実行中:引数3000
3000ms待ち完了
=======
cathed error:失敗例
myFuncの実行中:引数2000
2000ms待ち完了
=======
cathed error:失敗例
myFuncの実行中:引数1000
1000ms待ち完了
=======
cathed error:失敗例
全部が終了
今度は各awaitごとで出てくるエラー処理が行われる。
今回はこれらの例を通じて動作を見てきて、thenチェーンよりは可読性を簡潔にできることがわかった。