質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

1回答

2501閲覧

【JavaScript・Node.js】エラーが発生したPromiseをリトライするソースコードを簡潔に書きたい

dal

総合スコア38

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2020/11/06 08:34

非同期処理を実行し,エラーが発生した場合は最大3回までリトライを繰り返す,という動作を実現させたいと思い,以下のようなコードを実装しました.

こちらのコードで意図した動作は達成できるのですが,ネストが深く見辛く感じています.

javascript

1// 一部省略 2 3var requestPromise = require('request-promise'); 4 5var resp = await requestPromise.put(options).catch(async () => { 6 return await requestPromise.put(options).catch(async () => { 7 return await requestPromise.put(options).catch(async () => { 8 return await requestPromise.put(options).catch((e) => { 9 throw new Error("データ更新に失敗しました。 ErrorMessage : " + e.message); 10 }); 11 }); 12 }); 13}); 14 15// 一部省略 16

動作内容を変えずに,簡潔に書き換えることは可能でしょうか?
詳しい方がおりましたらご教授いただきたいです.よろしくお願いいたします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

awaitはPromiseという箱をかぶった非同期の箱を取り出して、
値を取り出して同期に戻すという役割があります。

なので最終的にPromiseなら何でも問題ありません。
純正のPromise流儀の書き方を続けて、
最後にawaitで待つような作りにしましょう。

Promise流儀の書き方は、
完了を.then.catchのメソッドで待ち受けるという
一次元配列的な書き方が出来る事を目的としたやり方ですので、
下記のようなコードが成立します。

js

1var resp = await requestPromise.put(options) 2 .catch(() => requestPromise.put(options)) 3 .catch(() => requestPromise.put(options)) 4 .catch(() => requestPromise.put(options)) 5 .catch(e => Promise.reject(new Error("データ更新に失敗しました。 ErrorMessage : " + e.message)));

上記のコードはPromiseの中にPromiseという風に
2重のPromiseの箱で包まれていますが問題ありません。
.then.catchの戻り値でPromiseがネストしている場合、
それらを自動suna的に全て取り除いて値の状態にしてくれます。

なのでユーザーとしては気にせずPromiseを返すような処理を
がんがん.then.catchメソッドでつないで行けば良いのです。


さて、上記のコードはベースです。
Promise作って.catchメソッドをぶら下げるだけなので、
いろんな書き方に派生できますね。

同じ処理に着目して代入しながらfor文を使うことも可能です。

js

1var putReq = requestPromise.put(options); 2for (var i = 0; i < 3; i++) { 3 // 毎回代入させることで1度ずつ挑戦を実現できる 4 // 代入しない場合、最初の挑戦に失敗すると同時並行で3個のリクエスト処理が同時に飛んでしまう 5 putReq = putReq.catch(() => requestPromise.put(options)); 6} 7putReq.catch(e => Promise.reject(new Error("データ更新に失敗しました。 ErrorMessage : " + e.message))); 8var resp = await putReq;

Lodaashなどのライブラリを使った関数型プログラミング的なアプローチならもう少し行数削れますね。
少々大道芸的ですが、reduce使ってワンライナーでやってみました。

js

1// まず1度も成功していない想定でPromise.rejectを作ってから.catchを4回ぶら下げる 2var resp = await [1, 2, 3, 4].reduce( 3 (p) => p.catch(() => requestPromise.put(options)), 4 Promise.reject() 5).catch(e => 6 Promise.reject(new Error("データ更新に失敗しました。 ErrorMessage : " + e.message)) 7);

【おまけ】 素直にasync/await構文で頑張る

async/await構文を使ってコードを書くとこんな感じになりますね。
Promiseの糖衣構文という制約上、catchを握りつぶすのでちょっとお行儀が悪いですね。

js

1var resp = null; 2for (let i = 0; i < 4; i++) { 3 try { 4 resp = await requestPromise.put(options); 5 break; 6 } catch (e) {} // お行儀が悪いがエラーは握りつぶす 7} 8if (resp == null) { 9 throw new Error("データ更新に失敗しました。 ErrorMessage : " + e.message) 10}

やはり.cacheメソッドをぶら下げながら、
ある程度の所まではPromiseで引っ張った方が綺麗に書けるでしょうね。

投稿2020/11/06 10:51

編集2020/11/09 18:50
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dal

2020/11/09 16:58

ご丁寧に回答いただき本当にありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問