2017-06-16 9 views
1

NPMライブラリの多くは正確なタイマーには使用できません。かなりシンプルです。ここで私が使用しているもののJSfiddleです:正確なタイマーをJavascriptで作成すると、時々負の間隔時間が発生する

http://jsfiddle.net/zryNf/9/

setPercentageBar(page) { 
    if (this.state.pagesById[page.id].active) { 
     let pagesByIdCopy = Object.assign({}, this.state.pagesById); 
     let pageCopy = pagesByIdCopy[page.id]; 

     let percent = (100.0/parseFloat(page.durationTime))/10; 
     pageCopy.percentage += percent; 
     this.setState({pagesById: pagesByIdCopy}); 

     pageCopy.progressBarNextAt += this.progressBarTime; // this.progressBarTime = 100 

     console.log('start time'); 
     console.log(pageCopy.progressBarStart); 
     console.log('next at'); 
     console.log(pageCopy.progressBarNextAt); 
     console.log('drift'); 
     console.log((new Date().getTime() - pageCopy.progressBarStart) % 100); 
     console.log('Date().getTime():'); 
     let currTime = new Date().getTime(); 
     console.log(currTime); 
     console.log('interval time'); 
     console.log(pageCopy.progressBarNextAt - currTime); 
     console.log('--------------------------------------------------------\n'); 

     if (pageCopy.percentage < 100) { 
     pageCopy.progressBarTimer = setTimeout(() => this.setPercentageBar(pageCopy), 
      pageCopy.progressBarNextAt - currTime); 
     } 
    } 
    } 

私が反応でこれをやっているように、それは正確なコードはありませんが、それはまったく同じ式です。

私はプログレスバーを更新するためにこれを使用しているので、100msの遅延を使用しています。スムーズに展開するにはプログレスバーが必要です。

私はstartTime、nextAt時間、ドリフト、およびインターバル時間を記録しており、常にうまく開始しました。しかし、ある時点で..間隔時間が負になると私はなぜか分からない!そして、それからすべてがその時点から乱れ始める。私はこの正確なタイマーの複数の数式を試してきましたが、最終的に毎回発生します。インターバル時間が負になると、それらはすべて負になります。

誰もがなぜそれを修正するためのアイデアがありますか?私は100msの各

+1

タイマーが正確なことはありません。..新しい日付はどちらでもありません... https://johnresig.com/blog/accuracy-of-javascript-time/ –

+1

あなたのフィドルで、あなたは「これは働いています!」と書いています。だから質問は何ですか? – trincot

+0

@trincotはペーストビンに投稿したログを見ています。あなたはある時点で間隔がマイナスになっているのを見ることができます。なぜそれをしているのか理解しようとしています。 – user1189352

答えて

1

setTimeoutコールバック関数が正確に希望で実行されるという保証はありませんで行くで最も5つのタイマーを持っています。ここ

は、いくつかの例では、

https://pastebin.com/Cpfpf1Gp

EDITをログに記録されています時間。その時点で他のJavaScriptコードが実行されている場合は、イベントキューの次のイベントが処理される前に完了する必要があります。タイマーイベントはそのようなイベントです。

だから、それがうまくあなたが次のシナリオを得ることかもしれません:0msとで

  • currTimeprogressBarNextAtは100で、あなたはsetTimeout(progressBarNextAt, 100)を呼び出し、0です。すべてが完璧です。
  • 1ms:イベントキューの次のイベントは、実際の処理のコールバックです。
  • 220ms:そのコールバックが終了し、イベントキューの次のイベントが遅いタイマーになります。あなたの関数setPercentageBarがもう一度呼び出されます
  • 221ms:progressBarNextAtが100から200に増加しました。 -21のインターバル時間を印刷します。

も、タイマーイベントは、マイクロタスクの形で、処理されます前予定のいくつかの非同期コードが存在する場合があります。例えば、第2の箇条書きの処理が即座に解決するいくつかの約束を有する場合、対応するthenコールバック関数はそのタスクの一部として実行され、それらのすべてが実行された場合にのみタイマーイベントがターンする。

また、JS以外の要素が特定のタスクの所要時間に影響することにも注意してください。マシンの負荷が高くなり、オペレーティングシステムがリソースを再割り当てすると、軽いJavaScriptタスクに影響が出る可能性があります。ブラウザーはまた、問題のウィンドウがフォアグラウンド上にないときにタイマーイベントの処理を遅らせる傾向があります。それでもなお他の理由があるかもしれません。

1

問題のコードは、何かを非常に単純にしているように見え、ちょっと複雑になりました。その複雑さを「ドリフト」計算で修正するのではなく、もっと簡単なアプローチをとるのはなぜですか?

  1. は、プログレスバーを更新する:

    重要な点は、これら二つのことを切り離すことです。

  2. 完了の割合または割合を計算する方法。

代わりに、いつでも呼び出すことができるupdate()関数を用意しましょう。常に正しいことを実行します。その計算は、私たちがそれをどれくらい頻繁に、あるいはいつ呼び出すかに全く依存しません。

また、setTimeout()またはsetInterval()をアニメーションに使用すると、かなり不安定な結果が得られる可能性があります。代わりにrequestAnimationFrame()を使用すると、よりスムーズなアニメーションを作成できます。 (それはまだ完璧ではないのですが、それはあなたがタイマーで買ってあげるよりはましだ。)

だから、このようなもののようになります。

function progressBar(duration) { 
 
    setValue(0); 
 
    var startTime = +new Date; 
 
    update(); 
 
    function update() { 
 
     var elapsed = +new Date - startTime; 
 
     if(elapsed > duration) elapsed = duration; 
 
     if(elapsed < duration) requestAnimationFrame(update); 
 
     setValue(elapsed/duration); 
 
    } 
 
    function setValue(fraction) { 
 
     var percent = Math.floor(fraction * 100); 
 
     document.getElementById('percent').innerHTML = 
 
      percent + '%'; 
 
     document.getElementById('filler').style.width = 
 
      fraction * 100 + '%'; 
 
    } 
 
} 
 

 
progressBar(5000);
#border { 
 
    border-color: black; 
 
    border-width: 1px; 
 
    width: 100%; 
 
    height: 20px; 
 
} 
 

 
#filler { 
 
    background-color: green; 
 
    width: 0; 
 
    height: 100%; 
 
}
<div id="border"> 
 
    <div id="filler"> 
 
     &nbsp; 
 
    </div> 
 
</div> 
 
<div id="percent"><div>

関連する問題