ここから本文です

JavaScriptで、setIntervalの処理をdoやforで3回繰り返すことができません。 お...

kiy********さん

2019/5/1800:05:18

JavaScriptで、setIntervalの処理をdoやforで3回繰り返すことができません。
お世話になります。

下のコードで「iが連続して大きくなり100を超えたら終了」というsetIntervalの処理を、doやforを使い3回繰り返したいのですがうまくいきません。
再帰的にmoveを呼出せばよいということを教えていただいたのですが、訳あってdoやforを使う必要があります。
moveの先頭で「f_time=false;」としているのですが、setIntervalがどんどん実行されてしまうようです。

var i=0;
var kai=0;
var f_time=true;

do{
if(f_time){
my_int=setInterval(move,100);
kai++;
}
}while(kai<=3);

function move(){
f_time=false;
i++;
・・・・・処理・・・・・
if(i>=100){
clearInterval(my_int);
f_time=true;
}
}

どこに問題があるかお教えいただけると助かります。
申し訳ありません。何卒よろしくお願いいたします。

この質問は、活躍中のチエリアン・専門家に回答をリクエストしました。

閲覧数:
45
回答数:
5
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

プロフィール画像

カテゴリマスター

ois********さん

リクエストマッチ

2019/5/1912:48:39

論理的には間違っていないんだけど、
マシンにおける物理的な限界があるから、
現実的には不可能な処理になっている。



■■■ 現状の処理内容 ■■■


質問のコードをそのまま実行すると、
まず最初に do{} の中身がひたすら繰り返される。
このとき do{} の中には、

────────────────
my_int=setInterval( move, 100 );
────────────────

というコードがあるけど、
最初に move が実行されるのは 100 ミリ秒後。
f_time が false になるのも move の中だから、
100 ミリ秒が経過するまでは f_time は true のまま。
だから、
do{} の中身のうち「kai++」だけがその場で実行される。

こうして kai は一瞬で 4 になるから、
setInterval() で最初の move が実行されるまえに do{} は終了し、
4つの setInterval() のタイマーが同時に始動した状態。
100 ミリ秒たった瞬間、
いっせいに4つの move が同時に実行され、
その後も4つの move が 100 ミリ秒おきに繰り返される。

さて、
ここで問題なのは、
clearInterval() でタイマーを止めるときに使う my_int。
do{} の中で4つのタイマーを一斉に始動した際、
変数 my_int は、
4つのタイマーの ID でつぎつぎと上書きされたから、
my_int が保持しているのは4つめのタイマーの ID となっている。

だから、
くり返される4つの move のなかで、
i が 100 を超えたときに clearInterval( my_int ) をしても、
止まるのは4つめのタイマーだけ。
3つのタイマーは永遠に動き続けることになる。



■■■ タイマーを1つずつ動かす ■■■


タイマーを1つずつ動かすには、
do{} のなかで1つめのタイマーが発動したとき、
その場で f_time を false にすればいい。

────────────────
var i=0;
var kai=0;
var f_time=true;

do{
if( f_time ){
f_time = false; // ★← これ
my_int = setInterval( move, 100 );
kai++;
}
}while( kai<=3 );

function move(){
i++;
if( i>=100 ){
clearInterval(my_int);
f_time=true;
}
}
────────────────

これで、
1回目の setInterval() が発動した直後から、
if( f_time ){ ~ } の中身は立ち入り禁止状態になり、
do{} の中身は空回りし続けることになる。
そして、
1つめの setInterval() が終わるとき f_time が再び true になるんで、
if( f_time ){ ~ } の中身が再び実行され、
2回目の setInterval が始まる・・・・・・・・・

・・・と理論上はこれで正解。

ところが、
現実問題として、
do{} の中身を絶え間なく空回りさせつづける処理は、
実際のマシンにさせると、
他の処理が一切できずにクラッシュしてしまう。
理論的には正しくても、現実的には不可能な処理になっている。

この場合、
do{} のループが絶え間なく繰り返されずに、
一定時間おきに繰り返されるのであれば、
クラッシュせずにちゃんと処理されるんで、
do{} をさらにタイマー処理に置き換えて、

────────────────
var i=0;
var kai=0;
var f_time=true;
var my_do, my_int;

my_do = setInterval( function(){ // ★← do{} じゃなく setInterval()
if( kai>=3 ){ clearInterval( my_do ) } // ★← kai は 3 まで
if( f_time ){
f_time = false;
my_int = setInterval( move, 100 );
kai++;
}
}, 20 );

function move(){
console.log( i++ );
if( i>=100 ){
i = 0; // ★← i はここで 0 にもどす
clearInterval(my_int);
f_time=true;
}
}
────────────────

とすれば、
意図したとおりの動きになる。

  • 質問者

    kiy********さん

    2019/5/1921:26:05

    ありがとうございます。
    とってもよく理解することができました。
    forやdoでsetIntervalを繰り返そうとしていましたが、それがなぜ無理なのかがわかりました。
    わかりやすい解説をしていただき感謝しております。
    本当にありがとうございました。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

質問した人からのコメント

2019/5/19 21:27:39

ご親切にわかりやすく解説していただき感謝しております。
勉強してみます。
本当にありがとうございました。

ベストアンサー以外の回答

1〜4件/4件中

並び替え:回答日時の
新しい順
|古い順

nic********さん

2019/5/1815:51:53

そのコードはブラウザをクラッシュさせる問題があるため、
ループ処理では。setInterval関数を使ってはいけません。

前の処理が終わったかどうかを考慮してくれる setTimeout関数を使うべきです。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

プロフィール画像

カテゴリマスター

leg********さん

リクエストマッチ

2019/5/1813:57:16

>setIntervalの処理を、doやforを使い3回繰り返したいのですが
うまくいきません。

それは、誰がやっても、うまくいかないでしょう!

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

プロフィール画像

カテゴリマスター

ama********さん

リクエストマッチ

2019/5/1811:33:40

できません。

(言葉で説明しても分かりにくいでしょうが)もしやるとしたら、そのループの部分を(ループにせず)関数にして、カウンターなど必要な変数はグルーバルに宣言し、setIntervalで呼び出された処理が終了時にインターバルをゼロmsで元の関数を呼び出すかたちにして下さい。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

yay********さん

2019/5/1802:05:03

「setInterval()は別スレッドで並列実行するのでその中の処理が終わるまで処理待ちになることがない」
ということが理解できてない。

0.1秒待ってmove()が実行されるよりdoループが3回回るほうが早い

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる