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

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

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

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

非同期処理

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

Q&A

解決済

1回答

221閲覧

関数とプロミスを使用したループ

tara-tail

総合スコア32

JavaScript

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

非同期処理

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

0グッド

0クリップ

投稿2019/09/12 10:09

関数とプロミスを使用して、ループ処理を行おうとしています。

非同期のループを実現させたく、プロミスを使用した関数のループを実現しようとしていますが、条件処理でresolveしません。

html

1<!DOCTYPE HTML> 2<html> 3 <head> 4 <script src="lib/jquery-2.2.0.min.js"></script> 5 <script src="js/test.js"></script> 6 </head> 7 <body> 8 <button type="button" onclick="xxx()">クリック</button> 9 </body> 10</html>

<test.js>

js

1let Looptest = function() { 2 this.num = 0; 3} 4 5Looptest.prototype = { 6 aaa: function() { 7 let defer = $.Deferred(); 8 setTimeout(function() { 9 console.log('setTimeout') 10 defer.resolve(); 11 }, 500); 12 return defer.promise(); 13 }, 14 bbb: function() { 15 let self = this; 16 let defer = $.Deferred(); 17 let promise = self.aaa(); 18 promise.done(function() { 19 // 5に達したら、resolveさせたい 20 self.num = self.num + 1; 21 if (self.num < 5) { 22 console.log(self.num) 23 self.bbb(); 24 } 25 else { 26 defer.resolve(); 27 } 28 }); 29 return defer.promise(); 30 } 31} 32 33function xxx() { 34 let lt = new Looptest(); 35 let promise = lt.bbb(); 36 promise.done(function() { 37 console.log('success!'); 38 }) 39}

発生している問題・エラーメッセージ

function xxx()を実行させると、以下のように途中までのコンソールログは表示されるのですが、最終的ゴールの「success!」が表示されません。

setTimeout 1 setTimeout 2 setTimeout 3 setTimeout 4 setTimeout

試したこと

bbb: function()内のself.num = self.num + 1;の位置を変えたりしました。

補足情報

function bbb()内の条件分岐でelseを設定しないと、「success!」は表示されるのですが、思ったような順番?に表示されません。

js

1 bbb: function() { 2 let self = this; 3 let defer = $.Deferred(); 4 let promise = self.aaa(); 5 promise.done(function() { 6 self.num = self.num + 1; 7 // 5に達したら、resolveさせたい 8 if (self.num < 5) { 9 console.log(self.num) 10 self.bbb(); 11 } 12 defer.resolve(); 13 }); 14 return defer.promise(); 15 }
setTimeout 1 success! setTimeout 2 setTimeout 3 setTimeout 4 setTimeout

###質問
どのようにすれば正確にresolveして「success!」まで辿り着けるのか、なるべくコードを変えずに、ご指摘をいただけると助かります。

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

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

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

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

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

guest

回答1

0

ベストアンサー

なるべくコードを変えずに

いい縛りですね! 燃えますね!
コードを変えた度合いの測定はレーベンシュタイン距離とかでしょうか?
当方は56でした!

js

1let Looptest = function() { 2 this.num = 0; 3} 4 5Looptest.prototype = { 6 aaa: function() { 7 let defer = $.Deferred(); 8 setTimeout(function() { 9 console.log('setTimeout') 10 defer.resolve(); 11 }, 500); 12 return defer.promise(); 13 }, 14 bbb: function(defer) { // 変更 15 let self = this; 16 let promise = self.aaa(); 17 promise.done(function() { 18 // 5に達したら、resolveさせたい 19 self.num = self.num + 1; 20 if (self.num < 5) { 21 console.log(self.num) 22 self.bbb(defer); // 変更 23 } 24 else { 25 defer.resolve(); 26 } 27 }); 28 return defer.promise(); 29 } 30} 31 32function xxx() { 33 let lt = new Looptest(); 34 let promise = lt.bbb( $.Deferred() ); // 変更 35 promise.done(function() { 36 console.log('success!'); 37 }) 38}

追記

↓これでレーベンシュタイン距離を23にすることができました!

js

1let Looptest = function() { 2 this.num = 0; 3} 4 5Looptest.prototype = { 6 aaa: function() { 7 let defer = $.Deferred(); 8 setTimeout(function() { 9 console.log('setTimeout') 10 defer.resolve(); 11 }, 500); 12 return defer.promise(); 13 }, 14 bbb: function(defer) { 15 let self = this; 16 letdefer = $.Deferred(); 17 let promise = self.aaa(); 18 promise.done(function() { 19 // 5に達したら、resolveさせたい 20 self.num = self.num + 1; 21 if (self.num < 5) { 22 console.log(self.num) 23 self.bbb(defer); 24 } 25 else { 26 defer.resolve(); 27 } 28 }); 29 return defer.promise(); 30 } 31} 32 33function xxx() { 34 let lt = new Looptest(); 35 let promise = lt.bbb($.Deferred()); 36 promise.done(function() { 37 console.log('success!'); 38 }) 39}

(ネタです)

投稿2019/09/12 10:21

編集2019/09/12 10:27
Lhankor_Mhy

総合スコア35865

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

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

tara-tail

2019/09/12 11:11 編集

Lhankor_Mhyさん、前回に引き続きありがとうございます。また、コードを変えずにと書いたのは、自分の理解力の低さのためです^^;。ご了承ください。 さて、Lhankor_Mhyさんのとおり修正したのですが、コンソールログが、「補足情報」に載せたような「success!」が3行目に表示されてしまいました。これは、こういう挙動なのでしょうか? まだ、ほかに聞きたいことがありますが、とりあえず、ここでは上記の点についてお伺いしたいと思います。
Lhankor_Mhy

2019/09/12 11:19

> 「success!」が3行目に表示されてしまいました。これは、こういう挙動なのでしょうか? 当方とは結果が異なるようです。 https://jsfiddle.net/Lhankor_Mhy/4cdsxrwp/ tara-tailさんの環境では、↑のコードを実行すると、『「success!」が3行目に表示され』ますか? 表示されるのであれば、同じコードで当方と違う結果なので、環境の問題かと思います。 表示されないのであれば、当方と同じ結果なので、ご提示いただいていない部分に原因があるのかもしれません。
tara-tail

2019/09/12 11:31

hankor_Mhyさん、大変申し訳ありません。「補足情報」で試した「else」を抜いたままになっていました。結果、うまく表示できました!本当に感謝です。 それで、一つ聞きたいのは、やはり引数の(defer)です。で、bbb()のほうでは、「let defer = $.Deferred();」を削除されていますのね。これは「aaa()」の方で定義されているから、余計だったのでしょうか?これの仕組みを教えてください、というのはちょっと乱暴ですので、なにかヒントを教えていただければ助かります。なぜ、引数がなかったら、うまくいかなかったのでしょう?「こういうものだ」と言ってくれても構いません。よろしくお願いします。
Lhankor_Mhy

2019/09/12 11:40

ご提示のコードは self.num == 1 の時ですが、 if文に入り条件不成立で self.bbb(); を呼び、 defer.promise() を返しますよね。 そのあと、 self.num == 5 の時ですが、 if文に入り条件成立で defer.resolve(); でプロミスを解決させるわけですが、この時の defer は let defer = $.Deferred(); ですから、この関数呼び出しに限ったスコープです。 なので、self.num == 1 の時に返した defer.promise() の defer とは別のものである、ということです。 これは想定と異なるのではないですか?
tara-tail

2019/09/12 23:31

Lhankor_Mhyさん、回答ありがとうございます。 aaa()もbbb()も同じ「let defer = $.Deferred();」にまとめた方が良い、という認識でよろしいでしょうか? 条件式のifとelseで同じdeferが返されていないという原因がわかりました。 ifの時は「aaa()」の「defer」を呼び出していて、elseの時は「bbb()」のdeferを呼び出している、という認識しています。 これは、全く想定していなかったことです。 同じにするには、引数を使用して,bbb()では「 let defer = $.Deferred(); 」を宣言しない(書かない)ということですよね? または、コンストラクタで、「this.defer = $.Deferred();」とした方が良いのでしょうか? もっと良い簡潔なアイデアがございましたら、教えてくいただけないでしょうか?
Lhankor_Mhy

2019/09/13 01:07

> aaa()もbbb()も同じ「let defer = $.Deferred();」にまとめた方が良い、という認識でよろしいでしょうか? うーん、どうでしょうか。そうすると defer のチェーンを切らないようにしないといけないですよね。 bbb() が aaa.done() の戻り値を返さなきゃいけないけど、bbb() は再帰するから……、かえって混乱しそうな……? > または、コンストラクタで、「this.defer = $.Deferred();」とした方が良いのでしょうか? それはわかりやすいと思います。 > もっと良い簡潔なアイデアがございましたら、教えてくいただけないでしょうか? async await で書いたほうが楽だと思います。前の質問を拝見するとトランスパイラをお使いなのでしょうから、使わない理由はないと思います。
tara-tail

2019/09/13 12:25

Lhankor_Mhyさん、迅速なご回答ありがとうございました。前のタランスパイラはVueのアプリを作成していたもので、今回のものとは違うのです。 最初にご回答していただいたものを元に、コンストラクタでDeferredを定義してみたり、いろいろ試してみたいと思います。まずは、ご回答のとおりにすればうまくいくので安心できました。また、よろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問