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

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

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

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

Q&A

2回答

2159閲覧

Promiseで用いてAPIを呼び出すコードがあるのですが、mapを用いて複数回にわけて実行するにあたりPromise.allを用いたのですが、実行順を指定することはできますか?

kinoshitaaa

総合スコア11

JavaScript

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

0グッド

0クリップ

投稿2018/03/03 12:51

以下のようなコードを実装しております。
csvには、APIコールに必要なパラメータを指定しており、その内容をもとに new Promiseの中で実行しております。

var fs = require('fs'); var csvSync = require('csv-parse/lib/sync'); var file = './addresses.csv'; let data = fs.readFileSync(file); const addresses = csvSync(data); Promise.all(addresses.map(address => { // ここでAPIを呼び出すために new Promise を実行 });

Promiseをつかった理由としましては、APIからのレスポンスに少し時間がかかるため、コールバックを上手く処理するためには
Promiseを使うと良いという記事があったため使っており、他の実装方法でも構いません。

また、csvの内容にそって複数回実行する必要があるため、Promise.allをつかっております。
こちらの内容にて実行はできたものの、CSV内で記載された内容を上から順で実行することを期待しておりましたが、
バラバラに実行されてしまっております。

非同期処理である以上、仕方ないのかもしれませんが、要件上、CSVの上から順に実行する必要があります。

Promise.all以外の実装方法でも構いませんが、CSVの上から順に実行するにはどのようにしたら宜しいでしょうか?

APIは独自実装したないようのため、記載ができず、
抽象的な内容ですみません。

補足できる範囲で補足させて頂きます。
宜しくお願い致します。

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

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

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

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

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

guest

回答2

0

CSVの上から順に実行する必要

と聞くと

(A) 非同期処理の起動順序を「1番目が完了してから2番目を開始・・・」としなければならない

(B) 各々の非同期処理の結果が順番に並んでいさえすれば処理そのものは並行して行ってもかまわない

のうち(A)であるように思えますが、実は(B)である可能性もあるような気もします。もし(B)ならturbgraphics200さんの回答のように結果の順序にさえ配慮すれば解決できると思いました。

一方もし(A)ならばPromise.allは使えず、もう一工夫する必要があろうかと思います。Promiseを使う前提で考えるなら・・・

###thenチェーン

javascript

1 2const addresses = [ 'a', 'b', 'c', 'd' ] 3 4function submit(address) { 5 return new Promise((resolve, reject) => { 6 ... 7 }); 8} 9 10addresses.reduce( 11 (p, address) => p.then(() => submit(address)), 12 Promise.resolve('dummy'));

thenチェーンを使うとsubmitは直前の仕事が完了してから起動されます。しかし、「何要素あるか」を意識できてその数だけthenを並べるなら見やすいですが、非同期処理の数が可変個数の場合は上記のようにreduceなどでthenチェーンを生成してやる必要がありそうです。

###async/await
async/awaitを使うと可変個数の非同期処理をawitしながらあたかも同期的に動かしているかのよう(に見える)書き方ができます。(ただ内部の動作はそう単純でもないところに注意が必要ですが)

Javascript

1async function submit(address) { 2 return new Promise((resolve, reject) => { 3 ... 4 }); 5} 6 7async fuction submit_serial(addresses) { 8 for (let address of addresses) { 9 await submit(address); // 非同期処理の完了を待つ 10 } 11 console.log('全部のアドレス処理が完了するとここを通過します'); // (B) 12} 13 14const addresses = [ 'a', 'b', 'c', 'd' ] 15submit_serial(addresses); 16// これ以降はsubmit_serialとは並行して動いてしまうことに注意... 17console.log('ここでは非同期処理がまだおわってないです...'); // (A)

(A)ではまだ非同期処理が完了しておらず(B)が完了したときに通過する箇所になる点が注意点です。またsubmit_serialではfor文を使っておりforEach/mapを単純に使えない点にも注意が必要です。

addresses.forEach(async a => await submit(a));

のように書くと順番に実行されるのかなと思ってしまいますが、実際はそうなりません。forEach関数はasync関数ではないので引数にasync関数async a => await submit(a)を渡してみてもforEachの方でそれをawaitしてくれません(当然といえば当然でした)。結果としてPromise.allと同じような動き(全ての非同期処理が同時にスタート)にしかなりません。

投稿2018/03/03 14:57

KSwordOfHaste

総合スコア18392

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

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

0

js

1Promise.all(addresses.map(address => { 2 return new Promise(~); 3}).then(results => { 4 results.forEach(result => { 5 // 6 }); 7});

とすれば、resultsには、mapで生成されたPromise配列の順番通りに結果が配列で渡されますので、あとはresultsを使って処理をすればいいと思います。

投稿2018/03/03 13:40

turbgraphics200

総合スコア4267

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問