I would like to measure time in browser javascript.
I use console.log(), console.debug() ...etc.
But console.timeEnd() behavior is similar to console.log(). It's wrote to console in case of "log" switch is on in browser's JS-Console.
I need to write time to console only if debug messages has switched on in browser.
Is it possible somehow?
There's nothing built in that will do that for you, but it's very easy to implement it yourself: Maintain a Map of labels to start times, and use Date.now() or performance.now() to get the start and end times.
Very roughly:
const debugTimeMap = new Map();
const debugTime = label => {
if (debugTimeMap.has(label)) {
console.warn(`Timer '${label}' already exists`);
} else {
debugTimeMap.set(label, Date.now());
}
};
const debugTimeEnd = label => {
const start = debugTimeMap.get(label);
if (start === undefined) {
console.warn(`Invalid debugTime label "${label}"`);
} else {
debugTimeMap.delete(label);
console.debug(`${label}: ${Date.now() - start} ms`);
}
};
const debugTimeMap = new Map();
const debugTime = label => {
if (debugTimeMap.has(label)) {
console.warn(`Timer '${label}' already exists`);
} else {
debugTimeMap.set(label, Date.now());
}
};
const debugTimeEnd = label => {
const start = debugTimeMap.get(label);
if (start === undefined) {
console.warn(`Invalid debugTime label "${label}"`);
} else {
debugTimeMap.delete(label);
console.debug(`${label}: ${Date.now() - start} ms`);
}
};
debugTime("x");
setTimeout(() => {
debugTimeEnd("x");
}, Math.floor(Math.random() * 1000));
(Look in the real console, and don't forget to turn on debug output in the console.)
Related
I have app witch visualize sorting alogrith i want to show user how much memory used each one of them when was runned it should be done on button click my stack is typescript and d3.js . I use Vite.js for building the app.
This is the button click code so far
let sortingInProgress = false
let timeInfo = '0.00 s'
const sortingPromise = new Promise<void>(resolve => {
START_BUTTON.addEventListener('click', async () => {
if (sortingInProgress) {
console.log('stoped')
return
}
sortingInProgress = true
START_BUTTON.disabled = true
SELECT_DATA_SIZE.disabled = true
SELECT_SORTING_ALGORITHM.disabled = true
const startTime = performance.now()
const sort = SelectAlgorithm(data, algorithmType)
await sort(updateBars)
const endTime = performance.now()
const totalTime = ((endTime - startTime) / 1000).toFixed(2) // get alogrithm running time in seconds
console.log(totalTime)
timeInfo = `${totalTime} s`
resolve()
})
})
sortingPromise.then(() => {
svg.selectAll('rect').style('fill', 'black')
sortingInProgress = false
SELECT_DATA_SIZE.disabled = false
SELECT_SORTING_ALGORITHM.disabled = false
SORT_TIME.textContent = timeInfo
})
Bear with me, I just started learning JS yesterday trying to make a HTML clock by putting multiple tutorials' results together.
I made two looping animations using 2 arrays, with the intent of switching between arrays depending on if it's earlier or later than 8pm. I would like for my code to constantly check if it's 8pm every X amount of seconds, and only re-run the script if the IF result or output is different than what it currently is.
const now = new Date();
if (now.getHours() > 20) { // Time checker!!!!!
var hat = ['A','B','C','D'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
} else {
var hat = ['1','2','3','4'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
}
I have tried setInterval however it re-runs the script even if the IF result has not changed, and messes up the animation.
I.E - if it's 6pm, it tries to play the animation from the start every 1 second and the frames get messed up.
Any advice or help would be great, thanks!
I tried to save your code.
const checkTimeDelay = 1000;
let isAbove8PM = null;
let curTimeHandler = null;
let intervalId = null;
// checking if is above 8 pm
const checkTime = () => {
const now = new Date();
if (now.getHours() > 20) {
return true;
}
return false;
};
const above8PMHandler = () => {
var hat = ['A','B','C','D'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
const before8PMHandler = () => {
var hat = ['1','2','3','4'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
// restart clock interval on based on new handler (above8PMHandler|before8PMHandler)
const rebaseClockInterval = () => {
clearInterval(intervalId);
intervalId = setInterval(curTimeHandler, 1000);
};
// main func, checks if we should change clocks handler (above8PMHandler|before8PMHandler)
const clockTick = () => {
const curTimeChecked = checkTime();
if (curTimeChecked === isAbove8PM) { return; }
isAbove8PM = curTimeChecked;
if (isAbove8PM) {
curTimeHandler = above8PMHandler();
} else {
curTimeHandler = before8PMHandler();
}
curTimeHandler();
rebaseClockInterval();
};
// start main func
setInterval(clockTick, checkTimeDelay);
I also provide some ideas here.
function setClockInterval() {
const hat1 = ['A', 'B', 'C', 'D'];
const hat2 = ['1', '2', '3', '4'];
let prevCheck = null;
let count = 0;
const checker = () => {
return new Date().getSeconds() > 20;
};
const next = () => {
count++;
};
const reset = () => {
count = 0;
};
const render = (content) => {
// console.log(`clockInterval ${content}`); // debug output
document.querySelector(".main").textContent = content;
};
const fn = () => {
const check = checker();
const arr = check ? hat1 : hat2;
// empty arr skip
if (arr.length <= 0)
return;
// restart count to 0
if (prevCheck !== null && prevCheck !== check)
reset();
render(arr[count % arr.length]);
prevCheck = check;
next();
};
return setInterval(fn, 1000);
}
// start interval
const clock = setClockInterval();
// stop
clearInterval(clock);
You can greatly simplify your code by removing everything from inside the if block that is repeated and running it afterward. You also need to get a new Date on each iteration, otherwise the array won't change when it gets to the designated time.
I have changed the condition check to be odd/even seconds to show how it swaps between arrays without losing the index.
// Global, could be kept inside closure
let a = -1;
// Function to run each iteration
(function f() {
// OP code
// let hat = new Date().getHours() > 18? ['A','B','C','D'] : ['1','2','3','4'];
// faster iteration as example
let hat = new Date().getSeconds() % 2? ['A','B','C','D'] :['1','2','3','4'];
a = (a + 1) % hat.length;
document.querySelector(".main").textContent = hat[a];
setTimeout(f, 1000);
})();
<div class="main"></div>
I have two working code snippets that I would like to link with if/else logic. The first part of the code receives a JSON response from a web API. JSON.TEMPERATURE is the key variable needed.
const fetch = require("node-fetch");
const api_url = 'https://www.placeholder_URL.com/api/getTemperature'
fetch(api_url)
.then((response) => {
return response.json();
})
.then((myJSON) => {
console.log(myJSON.TEMPERATURE); // **This returns a number between 8 and 15**
});
The second part of the code plays a MIDI note. In the case below, note # 60 which is the Middle C. C# would be note 61, D note 62 and so forth.
let easymidi = require("easymidi")
let output = new easymidi.Output("mindiPort", true)
let sendNote = (noteValue, duration) => {
output.send("noteon", noteValue)
setTimeout(()=> {
output.send("noteoff", noteValue)
}, duration);
}
setInterval(() => {
let noteValue = {
note: 60, // **need to change this number depending on JSON.TEMPERATURE**
velocity: 100,
channel: 1
}
sendNote(noteValue, 500)
}, 2000);
What I am looking to achieve is an if/else where the note played is dependent on JSON.TEMPERATURE.
Something like:
if JSON.TEMPERATURE == 8, play note 60
if JSON.TEMPERATURE == 9, play note 61
else, play note 55
I would also like to run the API request every 5 seconds.
Seems like all you need is an if statement such as
if(myJSON.TEMPERATURE == 8){
note = 60;
}
else if(myJSON.TEMPERATURE == 9){
note = 61;
}
else{
note = 55;
}
So just put this in place of your console.log part.
const fetch = require("node-fetch");
const api_url = 'https://www.placeholder_URL.com/api/getTemperature'
fetch(api_url)
.then((response) => {
return response.json();
})
.then((myJSON) => {
let note;
if(myJSON.TEMPERATURE == 8){
note = 60;
}
else if(myJSON.TEMPERATURE == 9){
note = 61;
}
else{
note = 55;
}
let noteValue = {
note: note,
velocity: 100,
channel: 1
}
sendNote(noteValue, 500)
});
let sendNote = (noteValue, duration) => {
output.send("noteon", noteValue)
setTimeout(()=> {
output.send("noteoff", noteValue)
}, duration);
}
You need to call the setInterval iniside of the .then of the fetch request, that way the note will be sent after the api request has finished and you have received the JSON response.
How you've currently implemented it it will call sendNote every 2 seconds. Additionally you want to do the api call every 5 seconds. This means that we want to clear the sendNote interval of the previous api call that's why the interval variable is there and we call clearInterval if interval is set.
Of course you can abstract it by putting some of this code into functions to make it look prettier but this is the gist of it
let interval;
const fetch = require("node-fetch");
const api_url = 'https://www.placeholder_URL.com/api/getTemperature'
setInterval(() =>
fetch(api_url)
.then((response) => {
return response.json();
})
.then((myJSON) => {
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => {
let note;
if (myJSON.TEMPERATURE == 8) {
note = 60;
} else if (myJSON.TEMPERATURE == 9) {
note = 61;
} else {
note = 55;
}
let noteValue = {
note: note,
velocity: 100,
channel: 1
}
sendNote(noteValue, 500)
}, 2000);
}), 5000);
I need to measure how long the following code calls the vibrate function in seconds and display the seconds which I have working. However, I don't know how to create a running total so that every time vibrate() is called, it both measures the length in seconds and then adds this to a running total.
function goodValue() {
startTime = new Date()
string1 = 'GOOD!!! :)'
displayValue('Angles', string1)
}
var startTime = {}
function badValue() {
var endTime = new Date()
vibrate1(1500)
string2 = 'BAD!!! :('
displayValue('Angles', string2)
var timeDiff = endTime - startTime //in ms
// strip the ms
timeDiff /= 1000
// get seconds
seconds = Math.round(timeDiff);
displayValue('TotalTime', + seconds);
}
This should now work. It's assuming that you call goodAngle() when the app recognizes a good angle, and badAngle() when the app recognizes a bad angle.
var totalTime = 0
var startTime = false
function goodAngle() {
if (startAngle) {
timeDiff = (Date.now() - startTime) / 1000
console.log('timeDiff: %s seconds', timeDiff)
totalTime += timeDiff
console.log('total timeDiff: %s seconds', timeDiff)
string1 = 'GOOD!!! :)'
displayValue('Angles', string1)
displayValue('BadPostureTime', Math.round(timeDiff))
startTime = false // So it can't be called again unless there's a badAngle first
}
}
function badAngle() {
if (!startTime) {
// Only set startTime if there isn't a current timer running
startTime = Date.now()
vibrate1(1500)
string2 = 'BAD!!! :('
displayValue('Angles', string2)
}
}
Skip to the expanded code snippet for the answer to this question. The rest of the examples address measuring other related metrics.
Measuring Each Individual Time
If you want to measure a function's execution time, you can wrap it in another function that uses console.time() and console.timeEnd():
function measure (fn, label = fn.name) {
return function () {
try {
console.time(label)
return fn.apply(this, arguments)
} finally {
console.timeEnd(label)
}
}
}
function delay (ms) {
const now = Date.now()
while (Date.now() - now < ms) { }
}
// wrap the function that needs to be tested
const timedDelay = measure(delay)
timedDelay(100)
timedDelay(10)
This measure() function has a few nice features:
The original function's return value is always preserved
The original function's thrown error is always preserved
If the original function throws an error, the time taken is still logged
The optional label argument is used to label the time that appears in the console
The label defaults to the name of the original function
The original function receives the context and arguments exactly as they were passed
To measure asynchronous functions, you can use the following, which can handle concurrent calls by incrementing a number used within the label in addition to the features above:
function measureAsync (fn, name = fn.name) {
let index = 0
return async function () {
const label = `${name} (${++index})`
try {
console.time(label)
return await fn.apply(this, arguments)
} finally {
console.timeEnd(label)
}
}
}
function delay (ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}
// wrap the async function that needs to be tested
const timedDelay = measureAsync(delay)
timedDelay(1000)
timedDelay(100)
timedDelay(500)
Measuring Total Time
Using the above two implementations, you can modify them with the Performance API to measure cumulative time instead:
Synchronous
function measureTotal (fn, label = fn.name) {
return Object.assign(function measured () {
try {
performance.mark(label)
return fn.apply(this, arguments)
} finally {
performance.measure(label, label)
const [{ duration }] = performance.getEntriesByName(label, 'measure')
const total = measured.total += duration
performance.clearMarks(label)
performance.clearMeasures(label)
console.log(`${label}: ${total.toFixed(3)}ms`)
}
}, {
total: 0
})
}
function delay (ms) {
const now = Date.now()
while (Date.now() - now < ms) { }
}
// wrap the function that needs to be tested
const timedDelay = measureTotal(delay)
timedDelay(100)
timedDelay(10)
timedDelay(50)
console.log('total:', timedDelay.total)
Asynchronous
function measureTotalAsync (fn, name = fn.name) {
let index = 0
return Object.assign(async function measured () {
const label = `${name} (${++index})`
try {
performance.mark(label)
return await fn.apply(this, arguments)
} finally {
performance.measure(label, label)
const [{ duration }] = performance.getEntriesByName(label, 'measure')
const total = measured.total += duration
performance.clearMarks(label)
performance.clearMeasures(label)
console.log(`${label}: ${total.toFixed(3)}ms`)
}
}, {
total: 0
})
}
function delay (ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}
// wrap the async function that needs to be tested
const timedDelay = measureTotalAsync(delay)
Promise.all([
timedDelay(1000),
timedDelay(100),
timedDelay(500)
]).finally(() => {
console.log('total:', timedDelay.total)
})
References
performance.mark()
performance.measure()
performance.getEntriesByName()
It is hard to tell what your code is supposed to do but I would advise making
a function which would wrap around your vibrate1 implementation.
The measureTime function takes a function as an argument (in your case vibrate) and
returns a function which has a property totalTime that records the execution
time. Note that it uses performance.now() instead of a Date object. See
https://developer.mozilla.org/fr/docs/Web/API/Performance/now for reference.
function measureTime(fn) {
const returnedFn = function measuredFunction (arg) {
const start = performance.now();
fn(arg);
const end = performance.now();
returnedFn.totalTime = returnedFn.totalTime + ((end - start) / 1000);
};
returnedFn.totalTime = 0;
return returnedFn;
}
const measuredVibrate = measureTime(vibrate1);
displayValue(measuredVibrate.totalTime);
So, I'm trying to model some long computation. for this purpose I'm computing the fibonacci number. In case when computation takes to much time I need to reject it.
The question: why TimeoutErrror handler doesn't work? How to fix the code?
const expect = require('chai').expect
const Promise = require('bluebird')
function profib(n, prev = '0', cur = '1') {
return new Promise.resolve(n < 2)
.then(function(isTerm) {
if(isTerm) {
return cur
} else {
n = n - 2
return profib(n, cur, strAdd(cur, prev));
}
})
}
const TIMEOUT = 10000
const N = 20000
describe('recursion', function() {
it.only('cancelation', function() {
this.timeout(2 * TIMEOUT)
let prom = profib(N).timeout(1000)
.catch(Promise.TimeoutError, function(e) {
console.log('timeout', e)
return '-1'
})
return prom.then((num) => {
expect(num).equal('-1')
})
})
})
const strAdd = function(lnum, rnum) {
lnum = lnum.split('').reverse();
rnum = rnum.split('').reverse();
var len = Math.max(lnum.length, rnum.length),
acc = 0;
res = [];
for(var i = 0; i < len; i++) {
var subres = Number(lnum[i] || 0) + Number(rnum[i] || 0) + acc;
acc = ~~(subres / 10); // integer division
res.push(subres % 10);
}
if (acc !== 0) {
res.push(acc);
}
return res.reverse().join('');
};
Some info about environment:
➜ node -v
v6.3.1
➜ npm list --depth=0
├── bluebird#3.4.6
├── chai#3.5.0
└── mocha#3.2.0
If I'm reading your code correctly profib does not exit until it's finished.
Timeouts are not interrupts. They are just events added to the list of events for the browser/node to run. The browser/node runs the next event when the code for the current event finishes.
Example:
setTimeout(function() {
console.log("timeout");
}, 1);
for(var i = 0; i < 100000; ++i) {
console.log(i);
}
Even though the timeout is set for 1 millisecond it doesn't appear until after the loop finishes (Which takes about 5 seconds on my machine)
You can see the same problem with a simple forever loop
const TIMEOUT = 10000
describe('forever', function() {
it.only('cancelation', function() {
this.timeout(2 * TIMEOUT)
while(true) { } // loop forever
})
})
Run in with your environment and you'll see it never times out. JavaScript does not support interrupts, it only supports events.
As for fixing the code you need to insert a call to setTimeout. For example, let's change forever loop so it exits (and therefore allows other events)
const TIMEOUT = 100
function alongtime(n) {
return new Promise(function(resolve, reject) {
function loopTillDone() {
if (n) {
--n;
setTimeout(loopTillDone);
} else {
resolve();
}
}
loopTillDone();
});
}
describe('forever', function() {
it.only('cancelation', function(done) {
this.timeout(2 * TIMEOUT)
alongtime(100000000).then(done);
})
})
Unfortunately using setTimeout is really a slow operation and arguably shouldn't be used in a function like profib. I don't really know what to suggest.
The problem appears because promises work in a "greedy" manner(it's my own explanation). For this reason function profib doesn't release event loop. To fix this issue I need to release event loop. The easiest way to do that with Promise.delay():
function profib(n, prev = '0', cur = '1') {
return new Promise.resolve(n < 2)
.then(function(isTerm) {
if(isTerm) {
return cur
} else {
n = n - 2
return Promise.delay(0).then(() => profib(n, cur, strAdd(cur, prev));
}
})
}
gman has already explained why your idea doesn't work. The simple and efficient solution would be to add a condition in your loop that checks the time and breaks, like thus :
var deadline = Date.now() + TIMEOUT
function profib(n, prev = '0', cur = '1') {
if (Date.now() >= deadline) throw new Error("timed out")
// your regular fib recursion here
}
Calling profib will either eventually return the result, or throw an error. However, it will block any other JavaScript from running while doing the calculation. Asynchronous execution isn't the solution here. Or at least, not all of it. What you need for such CPU-intensive tasks is a WebWorker to run it in another JavaScript context. Then you can wrap your WebWorker's communication channel in a Promise to get the API you envisioned originally.