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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Lodash

Lodashは、JavaScriptのユーティリティライブラリ。Underscoreの派生ライブラリで、配列・オブジェクトの操作に便利です。また、コードの可読性も高めることができます。

Node.js

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

Q&A

解決済

2回答

614閲覧

forEach中にreject発生した場合処理を抜ける (Promise)

tommyTeratail

総合スコア31

Lodash

Lodashは、JavaScriptのユーティリティライブラリ。Underscoreの派生ライブラリで、配列・オブジェクトの操作に便利です。また、コードの可読性も高めることができます。

Node.js

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

0グッド

0クリップ

投稿2018/02/19 04:46

編集2018/02/19 05:57

javascript

1function main(entity) { 2 _.forEach(entity, (v, k) => { 3 output(v) 4 .catch(err => { 5 logger.error(err.message); 6 // ここに来たらループを抜けたい 7 }); 8 }); 9 }; 10} 11 12function output(report) { 13 return new Promise((resolve, reject) => { 14 fs.writeFile('path', 'fileName', err => { 15 err ? reject(err.message) : resolve(); 16 }); 17 }); 18} 19 20main(db.findAll());

DBから取得
取得件数分、ファイルを出力
outputreject()した場合は、
ループを抜けたい

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

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

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

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

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

guest

回答2

0

たとえ途中rejectできたとしても、forEachだと全エントリー分outout()が実行されてしまうと思いますが。
直列化したい場合は、reduce()等を使うべきかと思います。

投稿2018/02/19 05:14

turbgraphics200

総合スコア4267

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

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

tommyTeratail

2018/02/19 05:26

forEachだと全エントリー分outout()が実行されてしまうと思います ↑その通りです これを避けたいです reduceを利用しても、catch内で抜けれないような気がします... どのような意味でしょうか?
turbgraphics200

2018/02/19 05:32

arr.reduce((promise, entry) => promise.then(output(entry)), Promise.resolve()).catch() こういう意味です。
tommyTeratail

2018/02/19 05:50

下記で実行して、 https://codepen.io/pen/ 1234とコンソールに表示されますが、 1のみで終わって欲しいです 検証の仕方が悪いのでしょうか? 検証コード ---- [1,2,3,4].reduce((promise, entry) => promise.then(output(entry)), Promise.resolve()).catch() function output(report) { return new Promise((resolve, reject) => { console.log(report); reject({message: 'ng'}); }); }
turbgraphics200

2018/02/19 06:04

すいません。output実行した結果になってしまうのでbindにするのを忘れてた。 [1,2,3,4].reduce((promise, entry) => promise.then(output.bind(null, entry)), Promise.resolve()).catch(_ => console.log(_));
tommyTeratail

2018/02/19 06:28

promise.then(...) この行が難しいので少し解説お願いします。
guest

0

ベストアンサー

promiseのみでやった場合、こんな感じになるわけですよ。

JavaScript

1var [v1, v2, v3, v4] = reports; 2output(v1) 3 .then(() => output(v2)) 4 .then(() => output(v3)) 5 .then(() => output(v4)) 6 .catch((e) => { 7 console.error(e); 8 });

まぁやりたいのはこういうことですね。
なんじゃこりゃ、配列の要素数が増減したらまるで対応出来ないじゃないか!

これが質問開始時の困っているポイントですね。
おっしゃる通りPromiseはこれが辛いです。
単にforEachやループを使ってしまうと、全てがほぼ同時に走ってしまいしっちゃかめっちゃかになってしまいます。

turbgraphics200さんがやってることは、reduceやforEachなどを使って
塊魂のようにpromiseを転がしながらthenを何度も宣言して付け足していく流れです。
reduceは一見びっくりしますが、よくよく調べると上記の事を着実にこなしているのがわかります。


しかし、初見さんにPromiseやるならreduceつかえと言われても辛いものがあるでしょう。
ES2017でasync/awaitが用意されていますので、こっち使えば普通のfor文で書けて楽です。

async/awaitは内部的にはPromiseを利用していますが、
このようにfor文を使ってまるで同期的であるかのように記述していけます。
今回はfor...ofを使って書いてみました。

JavaScript

1// awaitを使いたい場合は、asyncを宣言した関数でなければならない 2function async main(entity) { 3 try { 4 for (var v of entity) { 5 // awaitを指定するとpromiseのresolveが叩かれるまで待ってくれる 6 await output(v); 7 } 8 } catch (err) { 9 // awaitのpromiseがrejectになるとこっちに入る 10 logger.error(err.message); 11 } 12} 13 14function output (report) { 15 return new Promise((resolve, reject) => { 16 fs.writeFile('path', 'fileName', err => { 17 err ? reject(err.message) : resolve(); 18 }); 19 }); 20} 21 22main(db.findAll());

投稿2018/02/19 08:01

編集2018/02/19 10:58
miyabi-sun

総合スコア21158

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

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

tommyTeratail

2018/02/20 00:37

期待していたコードです いつも ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問