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

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

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

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

JavaScript

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

Q&A

解決済

3回答

1490閲覧

JSでオーディオを扱っていると、条件式が暴走しイベントが無限ループする

tmdayr

総合スコア5

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

JavaScript

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

0グッド

0クリップ

投稿2021/12/02 03:09

編集2021/12/02 03:16

前提・実現したいこと

ブラウザでJSを使って、オーディオを扱っています。
そこで、以下のコードを書いたのですが、問題が発生しています。

該当のソースコード

JavaScript

1audio.play(); 2 3audio.addEventListener('timeupdate', function() { 4 if (audio.currentTime < second) { 5 audio.currentTime = second; 6 } 7});

発生している問題

①オーディオが再生される
timeupdateイベントが発生する
addEventListenerが呼び出される
audio.currentTime < secondtrueになる
audio.currentTime = second;が実行され、timeupdateイベントが発生する
addEventListenerが呼び出される
audio.currentTime < secondfalseになる
audio.currentTime = second;が実行されず、timeupdateイベントは発生しない
addEventListenerは呼び出されない

となるのが筋だと思うのですが、
⑦がtrueになり続け、④〜⑥が無限ループしてしまいます。

なぜこの問題が発生しているのかわかりません。
原因と解決方法を教えてください。
お願いします。

試したこと

setIntervalで常に監視する方法も考えましたが、
そうじゃない感がすごいので実装はしていません。

発生したイベントを無効化する方法も考えましたが、
有効な手段には辿り着いていません。

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

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

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

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

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

miyabi_takatsuk

2021/12/02 03:36

second変数の定義はどこでしていますか?
Lhankor_Mhy

2021/12/02 03:39

second の値を教えてください。
tmdayr

2021/12/02 03:45

実際のコードは以下のようになっています。 また、```sourceR```の```max```は、 ```loadedmetadata```のタイミングで```sourceR.max = audio.duration;``` としています。 ```HTML <input type="range" min="0" value="0" step="any" id="sourceR"> ``` ```JS let sourceR = document.getElementById('sourceR'); audio.addEventListener('timeupdate', function() { if (audio.currentTime < sourceR.value) { audio.currentTime = sourceR.value; } }); ```
Lhankor_Mhy

2021/12/02 03:50

無限ループになる時の second の値を教えてください。
tmdayr

2021/12/02 03:51

0以外の時は必ず無限ループに陥ります。
skys215

2021/12/02 03:55

timeupdateの中にconsole.log(sourceR.value)を追加し、値を観察してみてください。 ちなみにjsfiddleやcodepanなどで問題を再現できるための最小限のコードを提供できると回答者にとって楽になると思います。
miyabi_takatsuk

2021/12/02 04:00

そのソースコードを、 質問本文に記載してください。 質問は編集できます。
int32_t

2021/12/02 04:00

確認してませんけども、数値と文字列を比較したり代入しているのと、sourceR.value の精度が高すぎると currentTime に代入するときに切り捨てが起きそうなのが気になりますね。
Lhankor_Mhy

2021/12/02 04:31 編集

>0以外の時は必ず無限ループに陥ります。 当方の環境では、小数点で四捨五入した時に切り捨てる値の時に問題が再現するように感じましたが、それは違いますか?
Lhankor_Mhy

2021/12/02 04:33 編集

あ、先に int32_tさんがご指摘されていたか。これが本命っぽいな……
guest

回答3

0

HTML

1<input type="range" min="0" value="0" step="any" id="sourceR">

実用上は 1ms 程度の精度でじゅうぶんでしょうから、step="0.001" にするのはいかがでしょうか。

それから、sourceR.value (文字列)ではなく sourceR.valueAsNumber (数値)を使うほうが適切です。

投稿2021/12/02 06:47

int32_t

総合スコア20661

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

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

tmdayr

2021/12/02 10:46

JSを使っていて、データ型を意識するとは思わなかったです。 ありがとうございます。
guest

0

ベストアンサー

audio.currentTimeは精度が小数第6位までなので、それよりも精度の高い小数を代入しようとすると、小数第7位を切り捨てた値が代入されます。

そのため、例えばsourceR.value1.2345678のとき、代入後のaudio.currentTime1.234567となり、audio.currentTime < sourceR.valuetrueとなってしまうため、無限ループが発生します。

精度は小数点以下が2,3桁くらいあればよいと思うので、sourceR.valueの小数第4位を四捨五入した値とaudio.currentTimeを比較し、条件を満たす場合はそれをaudio.currentTimeに代入します。

JavaScript

1document.addEventListener('DOMContentLoaded', function () { 2 let audio = document.getElementById('audio'); 3 let sourceR = document.getElementById('sourceR'); 4 5 audio.addEventListener('loadedmetadata', function () { 6 sourceR.max = audio.duration; 7 }); 8 9 audio.addEventListener('timeupdate', function () { 10 //console.log(audio.currentTime); 11 let value = Math.round(sourceR.value * 1000) / 1000; 12 if (audio.currentTime < value) { 13 audio.currentTime = value; 14 //console.log('changed!'); 15 } 16 }); 17}); 18

CodePen: https://codepen.io/luuguas/pen/NWaqWee

投稿2021/12/02 06:41

luuguas

総合スコア492

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

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

tmdayr

2021/12/02 10:47

HTMLの方をstep="0.000001"にして対応しました。 無限ルート問題は解決しました。 ありがとうございます。
luuguas

2021/12/02 11:11

stepの値を変えた方が楽ですね。勉強になりました。
guest

0

int32_tさんの言った通りに、比較する前に数値に変更してみたらどうですか?

JavaScript

1if (Math.round(parseFloat(audio.currentTime) < Math.round(parseFloat(sourceR.value)))) {

JsFiddle:https://jsfiddle.net/skys215/5tufazo9/14/

投稿2021/12/02 04:14

skys215

総合スコア910

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問