![](https://habrastorage.org/getpro/habr/post_images/593/5c6/3f4/5935c63f4124cba6513a634994e6f2ef.png)
あまり説得力のない物語の投稿では、「正確な」JSタイマーのさまざまな実装について説明しています。 材料は初心者向けに設計されています...猫へようこそ。
多くの人が指摘したように、この投稿の写真はダリの作品「時は流れている」の時計を示していますが、その選択は決してランダムで比meta的な性質ではありません。 というのは、JSのプログラミングのフレームワークでは、想定したとおりに時間が流れない場合があります。 JSは本質的にシングルスレッドであり、関数実行キューを生成します。キューは不可欠な順序を意味します。 また、計算の一部の段階がリソースを大量に消費する場合、必要なものと実行結果との間に明確な矛盾があります。 これは、ライブラリを使用しない一時的な監視の場合に特に重要です。 たとえば、3次曲線に沿った経時的な座標の変化を伴うトランジションの実行( イージング )、またはアプリケーションロジックへのリズミカルな呼び出しを使用して現在の状態を更新します。 数か月前、「週末プロジェクト」として、私は簡単なステップバイステップシーケンサー(wiki)を自分で作成することを選択しました。 この場合、ミスマッチは和解できず、0.5秒です。 解決策を探して、このトピックに関するすばらしい記事に出会いました。 そして、投稿自体は、ある意味では、無料の翻訳です。
その結果、「正確な」タイミングのタスクは、現在の関数の前の関数実行の遅延を差し引くことにより削減されます。 繰り返し間のシステム時間の差を測定し、次の呼び出しでそれを差し引くことができます。 簡単に聞こえますが、コードは次のとおりです。
var start = new Date().getTime(), time = 0, elapsed = '0.0'; function instance() { time += 100; elapsed = Math.floor(time / 100) / 10; if(Math.round(elapsed) == elapsed) { elapsed += '.0'; } document.title = elapsed; var diff = (new Date().getTime() - start) - time; window.setTimeout(instance, (100 - diff)); } window.setTimeout(instance, 100);
結果は非常に簡単です。 通常のタイマーと自動修正機能付きタイマーの動作を比較するための、ロシア語でのコメント付きのJSfiddleのデモを以下に示します。
このアプローチの最大の利点は、タイマーがどれほど不正確であるかという実際的な価値がないことです。これは、小さな一定の遅延(最後のデモ例の3-4msなど)を非常に簡単に補正できるためです。 単純なタイマーの不正確さは本質的に累積的ですが、反復ごとに累積し、最終的には地獄のような顕著な違いにつながります。
前述のように、オーディオアプリケーションを作成するときにこの問題が発生しました。 アプリケーション、これはもちろん非常に大声で言われ、むしろ別の教育的なミニプロジェクトです。 材料を研究した後、このコードは書かれました:
// "play/stop", function preciousTimer (step) { // , DateStamp var start = new Date().getTime(), time = 0, /* , ( )*/ it = 0; function instance () { // time += step; // var diff = (new Date().getTime()- start) - time; // if (it == 4) { it = 0; /* , . */ if (m == 8) { m = 0; }; for (var i = 0; i < 4; i++) { if (noteArr[i][m]) { sound[i].play(); }; }; m++; }; it++; // , // if (pause) { return; }; // , window.setTimeout(instance, (step - diff)); }; // instance(), // setTimeout(instance, step); };
誰かがすでに疑問に思っていた:コールスタックのオーバーフローはどうだろう。 この特定のケースでは、そのサイズは10から17ポジションの範囲であり、最新のブラウザーでは小さいです。 ただし、ペースの増加に伴い、または再計算された反復回数の増加に伴い、窒息攻撃が発生する可能性があるため、.tail()のような呼び出しの実装を検討する必要があります。 しかし、これはまったく異なる話です。
また、浮動小数点数、ページがロードされてから経過したかなりのミリ秒数(正確な定義ではない)を返すwindow.performance.now()メソッドに言及せずにはいられません。したがって、小数点以下には、すでにサブミリ秒の解像度があり、非常に優れています。 この値を使用すると、同様の方法で10分の1ミリ秒の精度で不一致を計算し、後続の反復をより正確に開始することができます。
ここでシーケンサーをライブで見ることができます: stepograph.hol.es (webkitが必要です)
投稿で部分的に使用された元の記事へのリンク: JavaScriptで正確なタイマーを作成する
ご清聴ありがとうございました!