ジェネレーターで無限ループ的に数字をyieldする関数を動かし、その関数を一度ストップし、また再開させたい

実現したいこと

1「あいうえお」という配列を用意し、
2 残り時間をを1秒ごとカウントダウンしながらにyieldするジェネレータを作成し、
3 0になったら配列のインデックスナンバーを更新していく。
4 要素の時間と、配列の中身を1~順に書き出していく(止めない限り無限に続く)

この際、「スタート」「ストップ」「スキップ」という3つのボタンを用意し、
スキップを押した時には、次の要素の飛んで、カウントダウンは最初から実行したい

前提

スキップボタンに、以下のコードを記述するのですが、うまくいきません。

skip_cntdown.addEventListener("click", function(){ // 一度動きを止める flg = false; // 配列の次のインデックスナンバーを入れ、 nth_in_arr ++; // フラグをtrueにし、再び動く準備をし、 flg = true; // 開始する play_cntdown(); });

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

エラーメッセージはでませんが、挙動がめちゃくちゃになります。
スキップボタンを何回かクリックしてみると、カウントダウン数字がめちゃくちゃな順番でめちゃくちゃなタイミングで表示されます。

該当のソースコード

HTML

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <link rel="stylesheet" href="style.css"> 7 <title>Document</title> 8</head> 9<body> 10 <div class="box"> 11 <p class="num"></p> 12 <p class="text"></p> 13 </div> 14 <button class="btn start_cntdown">Start</button> 15 <button class="btn stop_cntdown">Stop</button> 16 <button class="btn skip_cntdown">Skip</button> 17 <script src="main.js"></script> 18</body> 19</html>

css

1* {2 margin: 0;3 padding: 0;4}5 6.box {7 width: 500px;8 height: 200px;9 display: flex;10 gap: 10px;11}12.box > p {13 width: 200px;14 height: 100%;15 background-color: beige;16 font-size: 50px;17 display: flex;18 justify-content: center;19 align-items: center;20}21.box > p:nth-child(2) {22 width: 300px;23}/*# sourceMappingURL=style.css.map */

JS

1const num = document.querySelector(".num"); 2const text = document.querySelector(".text"); 3const start_cntdown = document.querySelector(".start_cntdown"); 4const stop_cntdown = document.querySelector(".stop_cntdown"); 5const skip_cntdown = document.querySelector(".skip_cntdown"); 6 7const arr = ["あ", "い", "う", "え", "お",]; 8// インデックスナンバーを格納する 9let nth_in_arr = 0; 10// カウントダウンを実行するためのフラグ 11let flg; 12 13// ジェネレーターを定義 14async function* value_generator(val1,val2,timeout = 1000) { 15 let index = val1 + 1; 16 // ↓val1, val2をそれぞれ交互に適応するため、 17 // このカウンタを2で割った余りを用いて切り替える 18 let cnt = 0; 19 text.textContent = "次の文字は"; 20 21 while(flg === true) { 22 if(index <= 1) { 23 cnt ++; 24 // 何回目か(カウンタ)の余りによって格納するのをval1かval2か判断する 25 if(cnt % 2 === 1) { 26 index = val2; 27 text.textContent = arr[nth_in_arr] 28 29 if(nth_in_arr >= arr.length - 1) { 30 // 無限にループする時は↓の設定 31 nth_in_arr = 0; 32 33 // 1に返ってこない時は↓の設定 34 // yield "おわり" 35 // return false; 36 }else{ 37 nth_in_arr ++; 38 } 39 40 }else{ 41 text.textContent = "次の文字は"; 42 index = val1; 43 } 44 yield index; 45 46 }else{ 47 index --; 48 yield index; 49 } 50 51 // fullfilledになるまで1秒待つ 52 await new Promise((resolve)=> { 53 setTimeout(resolve,timeout) 54 }); 55 } 56 57} 58 59// ジェネレーターから値を取得し、書き出すための関数 60async function play_cntdown() { 61 for await (const v of value_generator(3,2)){ 62 num.textContent = v; 63 } 64} 65 66// ↓後はそれぞれのボタンにさせたい動作を追加する 67start_cntdown.addEventListener("click",function(){ 68 flg = true; 69 play_cntdown(); 70}); 71 72stop_cntdown.addEventListener("click", function() { 73 flg = false; 74 nth_in_arr = 0; 75 num.textContent = ""; 76 text.textContent = ""; 77}); 78 79// 今回行き詰っているのがここです!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 80skip_cntdown.addEventListener("click", function(){ 81 // 一度動きを止める 82 flg = false; 83 // 配列の次のインデックスナンバーを入れ、 84 nth_in_arr ++; 85 // フラグをtrueにし、再び動く準備をし、 86 flg = true; 87 // 開始する 88 play_cntdown(); 89}); 90 91

試したこと

ジェネレーターの中で使う変数の中身がまだ残ってしまっているためかと思い、
ジェネレーターの中で、大きなif文を作り、
flgがtrueの時 → そのままプログラムを実行
flgはfalseの時 → ジェネレーター内の変数をことごとく初期化(変数 = "";)
という処理に変えてみましたが、結果は変わりませんでした。
こんな感じです

if(flg === true) { while(flg === true) { if(index <= 1) { cnt ++; // 何回目か(カウンタ)の余りによって格納するのをval1かval2か判断する if(cnt % 2 === 1) { index = val2; text.textContent = arr[nth_in_arr] if(nth_in_arr >= arr.length - 1) { // 無限にループする時は↓の設定 nth_in_arr = 0; // 1に返ってこない時は↓の設定 // yield "おわり" // return false; }else{ nth_in_arr ++; } }else{ text.textContent = "次の文字は"; index = val1; } yield index; }else{ index --; yield index; } // fullfilledになるまで1秒待つ await new Promise((resolve)=> { setTimeout(resolve,timeout) }); } }else{ while(flg === false){ index = ""; cnt = ""; } }

どなたかよろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

コメントを投稿

0 コメント