<button onclick="testHiresTime()">Test</button> <button onclick="recalibrate()">Recalibrate</button>
<div id="output"></div>
// Replacement to performance.now() that is based on SharedArrayBuffer. Used to get around the 5 microsecond resolution limit introduced as a response to the "Spy in the Sandbox" attack
// Returns the time in milliseconds since some arbtrary epoch, with around 4ns resolution.
// For more info: http://iss.oy.ne.ro/SpyInTheSandbox
// makeWorker is a little wrapper for generating web workers from strings
// Source: http://jsfiddle.net/bgrins/YUKSu/
function makeWorker(script) {
var URL = window.URL || window.webkitURL;
var Blob = window.Blob;
var Worker = window.Worker;
if (!URL || !Blob || !Worker || !script) {
return null;
}
var blob = new Blob([script]);
var worker = new Worker(URL.createObjectURL(blob));
return worker;
}
var isCalibrated = false;
var counterThread = {};
var sharedCounter = new SharedUint32Array(1);
var CALIBRATION_PERIOD_IN_MS = 100;
var millisecondsPerCount = 0.0;
// 16/Jul/2015 - Mark's suggestion to speed it up by removing an indirect read
var counterThreadCode = "var sharedCounter = {}; self.addEventListener('message', function(e) {" +
"var msg = e.data;" +
"var currentValue = 0;" +
"switch(msg.opcode) {" +
"case 'init': sharedCounter = new SharedUint32Array(msg.sab); break;" +
"case 'increment': do {" +
"currentValue = (currentValue + 1) | 0; " +
"sharedCounter[0] = currentValue;} while (true);break;} " +
"} ,false);"
// Bring up the thread
counterThread = makeWorker(counterThreadCode);
var msg = {opcode: "init", sab : sharedCounter.buffer};
counterThread.postMessage(msg, [msg.sab]);
function bufferBasedNow() {
// If the code was never calibrated, start everything up.
if (isCalibrated == false) {
// Calibrate the timer
var msg = {opcode: "increment"};
counterThread.postMessage(msg);
var startTime = performance.now();
var startCounter = sharedCounter[0];
console.log("Calibrate start: " + sharedCounter[0]);
do {} while (performance.now() - startTime < CALIBRATION_PERIOD_IN_MS);
var endCounter = sharedCounter[0];
console.log("Calibrate end: " + sharedCounter[0]);
// Save the scaling factor
millisecondsPerCount = CALIBRATION_PERIOD_IN_MS * 1.0 / (endCounter - startCounter);
// Feed back the value of performance.now() into the counter so they stay in sync
sharedCounter[0] = performance.now() / millisecondsPerCount;
isCalibrated = true;
}
// Everything is calibrated, we can measure time.
return sharedCounter[0] * millisecondsPerCount;
}
function testHiresTime() {
// Measure 100ms using performance.now(), see how much the counter-based timer measured it as.
var startTime = performance.now();
var startTimeBB = bufferBasedNow();
do {} while (performance.now() - startTime < 100);
document.getElementById("output").innerHTML = "Performance.now() measured " + (performance.now() - startTime)+ " ms, bufferBasedNow() measured " + (bufferBasedNow() - startTimeBB + " ms.");
}
function recalibrate() {
isCalibrated = false;
}
As a PRO member, you can drag-and-drop upload files here to use as resources. Images, Libraries, JSON data... anything you want. You can even edit them anytime, like any other code on CodePen.
Also see: Tab Triggers