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

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

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

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

Q&A

解決済

3回答

6406閲覧

JavaScript forループ内でのPromise

conei

総合スコア13

JavaScript

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

2グッド

5クリップ

投稿2019/02/22 07:52

JavaScriptのforループ内でPromiseを使った非同期処理を行いたいです

forループ内で非同期処理を呼び出し配列に戻り値を入れ、
処理後にその配列を使いたいのですが、どのようにすればよいのでしょうか?

function fnc1(num){ //非同期処理 return new Promise((resolve)=>{ window.setTimeout(() => { resolve(num); }, 3000); }); } function call(num){ let arry=new Array(); for(let i=0;i<5;i++){ fnc1(num+i) //非同期処理を呼び出し配列に入れる .then((res)=>{ arry[i]=res; }); } return arry; } console.log(call(0)); //配列を使ったその後の処理
GenbuHase👍を押しています

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

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

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

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

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

guest

回答3

0

どこかしらでは、resolve を待たないといけないと思います。

js

1function fnc1(num){ //非同期処理 2 return new Promise((resolve)=>{ 3 window.setTimeout(() => { 4 resolve(num); 5 }, 3000); 6 }); 7} 8 9async function call(num){ 10 let arry=new Array(); 11 for(let i=0;i<5;i++){ 12 arry[i] = await fnc1(num+i) //非同期処理を呼び出し配列に入れる 13 } 14 return arry; 15} 16 17call(0).then( x => console.log(x) ); //配列を使ったその後の処理

投稿2019/02/22 08:47

Lhankor_Mhy

総合スコア36074

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

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

Lhankor_Mhy

2019/02/22 08:49

ああ、そうか、Promise.all の方が早いですね。 rururu3 さんのご回答の方で。
miyabi-sun

2019/02/22 21:00 編集

いや、良いんじゃないですかね? for文らしく順番に動かしたいならこう書くのが自然です。 今回の例はsetTimeoutなのでPromise.allで十分に思えますが、 例えばHTTPリクエストを発射するという内容かつ、配列の中身が100個とかある場合は話が変わってきます。 並列で一気に処理すると負荷で大変な事になるので、こちらを採用する動機になるでしょう。
conei

2019/02/23 00:08

ありがとうございます、miyabi-sunさんもおっしゃっていますが、時と場合によりこちらを使うことも出てくると思うので非常に勉強になりました!
Lhankor_Mhy

2019/02/23 02:35

ああ、そうですね。パイプライン的に処理したい場合とかもありますか。 誰も回答しなかったですが、for await of はどうなんでしょうね。> miyabi-sun さん
guest

0

ベストアンサー

もっとうまい方法あるかもしれないけどPromise.all使ったらこんな感じかな

html

1<html> 2<head> 3<meta charset="UTF-8"> 4</head> 5<body> 6<script> 7function fnc1(num){ //非同期処理 8 return new Promise((resolve)=>{ 9 window.setTimeout(() => { 10 resolve(num); 11 }, 3000); 12 }); 13} 14 15function call(num){ 16 let pList = []; 17 for(let i=0;i<5;i++){ 18 pList.push( 19 fnc1(num+i) //非同期処理を呼び出し配列に入れる 20 ); 21 } 22 return(pList); 23} 24 25Promise.all(call(0)).then(function(values) { 26 console.log(values); 27}); 28</script> 29</body> 30</html>

投稿2019/02/22 08:18

編集2019/02/22 09:21
rururu3

総合スコア5545

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

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

shinji709

2019/02/22 08:31

.then((res)=>{ return(res); }) の3行はいらない気がします。 理由: Promise.resolve(42).then(v => v).then(v => v).then(v => v).then(v => {console.log(v)}); // => 42 Promise.resolve(42).then(v => {console.log(v)}); // => 42
rururu3

2019/02/22 09:20

shinji709さん 指摘ありがとうございます。そのとおりですね、ちょっと回答編集します。
conei

2019/02/23 00:05

ありがとうございます、最高のコードです!
guest

0

console.log(call(0)); //配列を使ったその後の処理

これは動作しない。
Promiseも非同期処理なので、
一度非同期処理というイベントと関数の世界に足を踏み入れたら二度と帰ってこれない。

call関数の戻り値をPromise値で返すようにしてあげて、
call(0).then(fn)という風に後続の処理を関数化して渡してやる必要がある。


並列処理で構わないならPromise.allがいいね。
イディオムを駆使して一撃で済ませるとこんな感じ。

JavaScript

1const fn1 = num => new Promise(resolve => 2 setTimeout(() => resolve(num), 3000) 3); 4 5const call = num => Promise.all( 6 Array(5).fill(0).map((_, i) => num + i).map(fn1) 7); 8 9call(0).then(console.log); 10// Promise {<pending>} 11// 3秒待ってから: [0, 1, 2, 3, 4]

問題は直列処理。
こんな風に.thenメソッドを叩きながら数珠つなぎにしていく

JavaScript

1// 長いので500ms間隔に変更 2const fn1 = num => new Promise(resolve => 3 setTimeout(() => resolve(num), 500) 4); 5 6const call = num => { 7 // とりま空のPromiseを宣言 8 let promise = Promise.resolve(null); 9 const results = []; 10 for (let i = 0; i < 5; i++) { 11 // このように代入していかないと直列繋ぎで実行してくれない 12 promise = promise.then(() => 13 fn1(num + i).then(it => results.push(it)) 14 ) 15 } 16 // やる事が全部終わったら結果をresultsにすげ替える 17 return promise.then(() => results); 18} 19 20call(0).then(console.log); 21// Promise {<pending>} 22// 500ms*5の約2.5秒ほど待ってから: [0, 1, 2, 3, 4]

実はES2017で追加されたasync/awaitという糖衣構文でPromiseを同期処理っぽく書く事が出来る。
Lhankor_Mhyさんの回答はその書き方であり、普通にfor文で処理出来るようになる。

JavaScript

1// やはり長いので500msに 2const fn1 = num => new Promise(resolve => 3 setTimeout(() => resolve(num), 500) 4); 5 6// なんだこの平易なコードは!? 7const call = async num => { 8 const results = []; 9 for (let i = 0; i < 5; i++) { 10 results.push(await fn1(num + i)); 11 } 12 return results; 13}; 14 15call(0).then(console.log); 16// Promise {<pending>} 17// 500ms*5の約2.5秒ほど待ってから: [0, 1, 2, 3, 4]

このasync版のcall関数は上記のコードとほぼ同様の動きをしてくれる。

投稿2019/02/22 20:48

編集2019/02/22 21:36
miyabi-sun

総合スコア21158

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

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

conei

2019/02/23 00:18

ありがとうございます、1つ目のコードがハイレベルすぎてちょっと私では使いこなせそうになかったです涙
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問