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

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

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

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

Q&A

解決済

3回答

13752閲覧

JavaScriptで非同期処理を再帰的に逐次処理したい

knp

総合スコア12

JavaScript

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

0グッド

2クリップ

投稿2017/08/21 07:38

JavaScriptで非同期処理を再帰的かつ逐次処理しようとしています。
下記のサンプルコードで再帰部分は逐次処理になったのですが、最初のrecursiveFuncに続くthen部分が1つ目の再帰処理が終わった時点で実行されてしまいます。全ての再帰処理が終わったら"done"と表示するにはどうしたら良いでしょうか?

JavaScript

1var arr = ["1","2","3","4","5","6","7","8","9","10"]; 2 3recursiveFunc(arr).then(function(){console.log("done");}); 4 5function recursiveFunc(arr){ 6 while (arr.length > 0 ) { 7 return new Promise((resolve,reject)=>{ 8 var tmpArr = arr.splice(0,3); 9 var entryTimestamp = Date.now(); 10 setTimeout(function(){logger(tmpArr,entryTimestamp);resolve()},1000); 11 }).then(function(){recursiveFunc(arr)}); 12 } 13} 14 15function logger(arr, timestamp){ 16 console.log(JSON.stringify(arr)+timestamp); 17}

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

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

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

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

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

guest

回答3

0

ベストアンサー

js

1 }).then(function(){recursiveFunc(arr)});

の部分を、

js

1 }).then(function(){return recursiveFunc(arr)});

とすればよいのでは、と思います。
Promiseをreturnするのがポイントですね。

投稿2017/08/21 08:08

othersight

総合スコア356

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

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

knp

2017/08/21 08:50 編集

回答ありがとうございます。確かにそのように修正したら意図した動作になったのですが、recursiveFuncの中でPromiseをreturnしているのにダメな理由はなんでしょうか?
othersight

2017/08/21 09:55

`recursiveFunc(arr)`の戻り値がPromiseであっても、`function(){recursiveFunc(arr)}`の戻り値は、return文が無いため`undefined`となってしまうからです。 意図した動作にするには、`then()`の引数をPromiseを返す関数にする必要がありますが、元のコードでは`.then()`の引数が結果的にundefinedを返す関数となっていたため、`.then()`が直ちにresolveしてしまった、ということになります。 なお、一点補足ですが、`new Promise((resolve, reject)=>{...})`の`resolve`に渡した引数(一つ)は、`.then()`の引数の関数に渡されるという性質がありますので、上記のコードについては、 ```js setTimeout(function(){logger(tmpArr,entryTimestamp);resolve()},1000); }).then(function(){recursiveFunc(arr)}); ``` の部分を ```js setTimeout(function(){logger(tmpArr,entryTimestamp);resolve(arr)},1000); }).then(recursiveFunc); ``` のように修正しても意図した動作になります。
knp

2017/08/22 04:37

次のコードで実験しておっしゃっている意味がわかりました。再帰の内部はnew Promise.then()となっているので一つ前の結果を待つ逐次処理にはなっているけれど、呼び出し元に結果が伝わらない書き方になっていたのですね。 var p = Promise.resolve(); p.then(function(){asyncFunc("1")}).then(function(){asyncFunc("2")}); //asyncFuncを呼び出した直後に新しいPromiseオブジェクトが作られ、thenの実行結果として返るので"順番"に処理されるが、asyncFuncの結果を待たずに次のthenが実行される。asyncFuncが返すPromiseオブジェクトは無名関数の中で消滅する。 p.then(function(){return asyncFunc("1")}).then(function(){return asyncFunc("2")}); //asyncFuncが返すPromiseオブジェクトをthenの実行結果に引き渡すので、asyncFuncの結果を待つ逐次処理になる。 function asyncFunc(text){ return new Promise((resolve)=>{ setTimeout(function(){console.log("log:"+text);resolve()},1000); }) }
othersight

2017/08/22 04:46

まさしく、そういうことですね。解決できたようで、何よりです。
guest

0

Promise は azu さんが素晴らしいリファレンスを公開して下さっているので、是非、参考にすることをお勧めします。
http://azu.github.io/promises-book/#promise-sequence

Re: knp さん

投稿2017/08/21 08:31

think49

総合スコア18156

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

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

knp

2017/08/22 04:38

ありがとうございます。参考になりました。
guest

0

再帰関数にしなければいけない理由はありますか?
特に理由がないのであれば、以下のような書き方でも実現できます
もし参考になるのであればどうぞ。

javascript

1function recursiveFunc(arr){ 2 var p = Promise.resolve() 3 arr.forEach(function(target){ 4 p = p.then(function(){ 5 return new Promise(function(resolve){ 6 setTimeout(function(){ 7 console.log(target) 8 resolve() 9 },1000); 10 }) 11 }) 12 }) 13 return p 14} 15 16var arr = ["1","2","3","4","5","6","7","8","9","10"]; 17recursiveFunc(arr).then(function(){console.log("done");});

async/awaitを使用可能であれば、以下のように書きます

javascript

1const recursiveFunc = async (arr) => { 2 for(const target of arr){ 3 await new Promise((resolve) => { 4 setTimeout(()=>{ 5 console.log(target) 6 resolve() 7 },1000); 8 }) 9 } 10} 11 12var arr = ["1","2","3","4","5","6","7","8","9","10"]; 13recursiveFunc(arr).then(function(){console.log("done");}); 14

投稿2017/08/21 13:41

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

knp

2017/08/22 04:38

色々な書き方ができますね。参考になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問