2017年2月26日日曜日

間隔調整式setIntervalを作成しました

昨日の記事ではsetIntervalの間隔がわりとアバウトで、しかもズレが累積されていくということをご紹介しました。
ズレを考慮して次回までの間隔を自動的に調整するタイプのsetIntervalを作成しました。


以下ソース
<html>
<title>シングルループ</title>
<body>
<input id=inp value=100>
<button id=btn0>開始</button>
<button id=btn1>停止</button>
<button id=btn2>objIV</button>
<div id=div></div>
</body>
<script>
resizeTo(550,170)
objIV = 0
btn0.onclick=function(){
btn1.onclick()
var st=(new Date()).getTime(), 回数=0, キリ='', 間隔=inp.value-0, 計算上='', MMA='', 合計=0, arr=[], arrI=0
objIV = set間隔調整式Interval(function(){
var nt=(new Date()).getTime()
div.innerText = (nt - st) + 'ミリ秒経過\n' + キリ + '\n' + 計算上 + '\n' + MMA
if((++回数 % 10)==0){
キリ = 回数+'回目:'+((nt-st) / 回数 / 間隔)
合計 += arr[arrI] = nt - ((Math.round((nt - st) / 間隔) * 間隔) + st)
計算上 = '計算とのズレ=nt - ((Math.round((nt - st) / 間隔) * 間隔) + st)='+arr[arrI]
arrI++
MMA = 'max:' + Math.max.apply(null,arr)+' min:' + Math.min.apply(null,arr)+' average:'+(合計/arrI)
}
}, 間隔)
}
btn1.onclick=function(){ objIV && objIV.clearInterval(objIV) }
btn2.onclick=function(){ confirm(objIV) }
set間隔調整式Interval=function(){
var getTime=function(){return (new Date()).getTime()}
return function(fun, 間隔){
var 開始=getTime()
var メイン=function(){
if(arguments.callee.終了){return}
fun()
setTimeout(メイン, 間隔 - ((getTime() - 開始) % 間隔))
}
メイン.clearInterval=function(){ this.終了 = true }
メイン()
return メイン
}
}()
</script>
</html>


動作画面








昨日の実験では(10ミリ秒などに比べれば、比較的)間隔が長い分精度が悪くなりにくいと思っていた1000ミリ秒でさえズレのaverageが12ミリ秒、maxだと48ミリ秒!なので「調整できてないじゃん…」と思われるかもしれませんが、この関数の目的はあくまで「初回起動時から計算して次の起動開始時刻がジャストなタイミングになるように間隔を調整することで、ズレの累積を回避する」なので、これで良いのです。

ズレを限りなく0に近づけたいと思うなら、もう少し処理を増やして調整できるかもしれませんが、とりあえず累積的に増えていく点は解消できているので良しとします。

ちなみに、例えば間隔を10ミリ秒とかにして20ミリ秒ぐらいかかる処理を繰り返し実行させるようにすると当然10ミリ秒間隔では処理が実行できません。
計算上ムリなタイミングの分は省略するようにしています。

0 件のコメント:

コメントを投稿