Nodejs function running every 2 minutes lost over time - javascript

This is quite hard problem to describe.
I have a koajs app with a function which is created in multiple instances (10-1000 range) every 2 minutes. this scheduled job created on app startup. I use koajs because i need a few simple api endpoints for this app. It is running well for first 3-5 hours and then the count of created instances starts to decrease and some of the log output disappears.
Here is the minimal sample based on actual code:
server.ts
const bootstrap = async () => {
process.setMaxListeners(0); //(node:7310) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
//appears on app startup (however seems like this setMaxListeners(0) doesnt affect anything since the warning persist)
const app = new Koa();
app.use(async ctx => {
ctx.body = "Welcome to my Server!";
});
app.listen(port);
new Main().run();
};
bootstrap();
main.ts (tried: cron npm package, node-scheduler, setInterval, recursive setTimeout) to run the scheduledJobWrapper.
isStarting: boolean = false;
async run() {
logger.info(`running the app, every 2 minutes`);
//let that = this;
// new CronJob(`*/2 * * * *`, function () {
// that.scheduledJobWrapper();
// }, null, true, 'America/Los_Angeles');
const interval = 2 * 60 * 1000;
setInterval(() => {
this.scheduledJobWrapper();
}, interval);
}
async scheduledJobWrapper() {
logger.info("here scheduledJobWrapper");
let args = {};
//some irrelevant logic to set the arguments
await this.scheduledJob(args);
}
async scheduledJob(args) {
try {
logger.info("starting");
if (!this.isStarting) {
this.isStarting = true;
const runningCount = Executor.tasks.length; //Executor.tasks is a singleton containing some info about tasks. details are irrelevant. the point is it contains the active tasks.
const tasksLimit = 100;
if (runningCount < tasksLimit) {
for await (const i of Array(tasksLimit - runningCount).keys()) {
if (Executor.tasks.length > 20)
await global.sleep(5 * 1000);
this.startWrapper(args); //calling main task here
}
}
this.isStarting = false;
logger.info(`Started: ${Executor.tasks.length - runningCount}`);
}
} catch (e) {
logger.error("Error running scheduled job: " + e.toString());
}
}
In this example the problem manifests as following:
All work as expected first 3-5 hours, later for each time the scheduled function called:
logger.info("here scheduledJobWrapper"); does now show any output.
logger.info("starting"); not in the output
this.startWrapper does run and the code inside it is being executed.
Despite that the code inside of this.startWrapper is still running, the count of newly created jobs is slowly decreasing.
Hardware (RAM/CPU) is not getting any significant load (CPU under 10%, RAM under 20%)
Any clue on possible reason?
nodejs: 12.6.0
Thanks!
UPDATE
it seems like that with the usage of setInterval the app is running OK for a longer time (6-24 hours), but after that the problem still starts.

The issue is with setInterval function. It gets slow down with the time. It has wierd behavior too. You can create custom setInterval using setTimeout or use third-party module and give try.
Sample setInterval Implementation.
const intervals = new Map();
function setInterval(fn, time, context, ...args) {
const id = new Date().getTime() + "" + Math.floor(Math.random() * 10000);
intervals.set(
id,
setTimeout(function next() {
intervals.set(id, setTimeout(next, time));
fn.apply(context, args);
}, time)
);
return id;
}
function clearInterval(id) {
clearTimeout(intervals.get(id));
}
setInterval(console.log, 100, console, "hi");
You can also enhance, by adding delta time loss in next setTimeout.
Meaning if time loss, run next setTimeout earlier.

First of all, It will be better to move instance of Main() in listen scope:
app.listen(port, () => {
new Main().run();
});
I don't know how good idea is to run setInterval function in the backend side. It's better to extract this logic and move it in cron job.
Are we sure that the machine can run 100 tasks? Please count the tasks by order and see when the problem starts. Probably you can not schedule 100 tasks and exists one limit somewhere

Related

Stop Cron Job inside the scheduler Node.js

I've created a cron-job to run a task and I want it to stop at some specific condition inside the scheduler, but it is not working.
How can I stop cron job inside the scheduler?
Here is my code:
// cron-job.js
const cron = require('node-cron');
const scheduler = cron.schedule('* * * * *', () => {
let result = fetchResultAfterSomeOperation();
if (result < 20) {
scheduler.stop(); //------------------------ It doesn't work
}
}, {
scheduled: false
});
scheduler.start();
How cron jobs created ?
Actually, Cron jobs are created from parent process. So parent process can have ability or feature to kill or suspend the child processes. So here node-cron may works in this way.
Now come to your issue, you have submitting cron task using cron.schedule(time,callback). Now callback is going to run on separate child process. So even if you're using scheduler object to stop the cron task, it wont work. The scheduler can stop the child process from main process (i.e cron.js file).
So I advise you to refactor your code.
As suggested by #Faizul Ahemed, you may change the code to something like this:
const cron = require('node-cron');
let result = null
const seachFunction = () => {
if (!result) fetchResults();
}
const scheduler = cron.schedule('*/10 * * * * *', searchFunction, { scheduled: false });
scheduler.start();
setTimeout(() => { scheduler.stop() }, 5 * 60 * 1000)
The above code will cause the fetchResults function to fetch/get data every x time for a duration of y set by the setTimeout.

Is there a way to loop an Observable and use the previous iteration to influence the next?

I'm brand spakin' new to rxjs, and would like to use it to build a video downloader. The intention is to run it 24/7 and automatically record an occasional livestream for later watching. Here is what I have so far.
import { BehaviorSubject, from, defer, of } from "rxjs";
import { delay, mergeMap, repeat, tap } from "rxjs/operators";
const downloader = url => {
const defaultDelay = 1000;
const maxDelay = 10000;
const delayTime = new BehaviorSubject(defaultDelay);
/*
* Simulated download output.
*
* #return {String|Number} potentialOutput
* A {Number} 1 means "FAILURE, stream is offline."
* A {String} means "SUCCESS, video was downloaded."
* 1 is the most likely value returned
*
* greets https://stackoverflow.com/a/8877271/1004931
*/
function randomWithProbability() {
var potentialOutput = [1, 1, 1, 1, 1, "/tmp/video.mp4"];
var idx = Math.floor(Math.random() * potentialOutput.length);
return potentialOutput[idx];
}
/**
* Simulated download. Returns a promise which resolves after 1 second.
*/
const download = url => {
let downloadP = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(randomWithProbability());
}, 1000);
});
return from(downloadP);
};
/**
* Conditionally adjust the delay inbetween download attempts.
* - If the video downloaded successfuly, reset the timer to it's default.
* (in case the stream went down by error, we want to record again ASAP.)
* - If the video stream was offline, increase the delay until our next download attempt.
* (we don't want to be rude and flood the server)
*/
const adjustTimer = (ytdlOutput) => {
if (typeof ytdlOutput === 'string') {
delayTime.next(defaultDelay); // video stream exited successfully, so reset in case the stream starts again
} else {
let adjustedTime = (delayTime.getValue() * 2 > maxDelay) ? maxDelay : delayTime.getValue() * 2;
delayTime.next(adjustedTime); // video stream exited abnormally, likely due to being offline. wait longer until next attempt
}
};
/**
* The Observable.
* 1. Start with the URL of the video stream
* 2. delay by the time defined in delayTime
* 3. download, merging the download observable with the parent observable.
* 4. adjust the delayTime based on download output.
* 5. repeat the process indefinitely.
*/
const stream = of(url)
.pipe(
delay(delayTime.getValue()),
mergeMap(download),
tap(res => {
adjustTimer(res);
}),
repeat()
)
stream.subscribe(val => {
console.log(
`download result:${val}, delayTime:${delayTime.getValue()}`
);
});
};
downloader("https://example.com/files/video.mp4");
(Stackblitz)
The problem I'm having is that the {BehaviorSubject} delayTime is not getting updated on every iteration of my loop. delayTime is getting updated, as indicated by delayTime.getValue() being called in the subscriber's callback, but the changes aren't having an effect in the memory(?) of the observable/subscriber(?).
Instead, I'm seeing that delayTime in the scope(?) of the observable is staying the same, as it was when it was first subscribed to. In the observable's world, there is no update to the BehaviorSubject's value, as I want there to be.
And this is where I'm stuck. How can I refactor my code to have a delay timer which changes over time, and effects the delay until the next download attempt?
Ignore rxjs for a moment, and look at this code pretending you don't know what any of these functions mean:
const stream = of(url)
.pipe(
delay(delayTime.getValue()),
mergeMap(download),
tap(res => {
adjustTimer(res);
}),
repeat()
)
An anonymized, simple version would be
someFunc(delayTime.getValue())
The problem here is that delayTime.getValue() gets evaluated directly, not when someFunc runs. The same is true for your code above: the evaluation happens when the stream variable is created, not on every "iteration" (better word: emission).
The delay operator works only with a fixed delay. For your purpose you want to use delayWhen, which is evaluated for each emission:
delayWhen(() => timer(delayTime.getValue())
Notice, however, that we need to return a notifier observable rather than the desired delay in ms.
As a final note, accessing getValue is a red flag for not using observables correctly. That's also why we don't actually use the arguments provided to the callback in delayWhen. Your code could do with refactoring to make it properly reactive, but that is beyond the scope here.

How to restart web workers when computer restarts from sleep mode?

I have a simple webworker which keeps the current time of timezone using setInterval
setInterval(() => {
userTimezoneTimestamp = userTimezoneTimestamp + 1000
postMessage(userTimezoneTimestamp);
}, 1000);
It works fine until I put my machine on sleep mode. When I restart the machine from sleep mode, the time which I get from this worker is older.
How can I restart my web worker only when the machine starts up from sleep mode?
There doesn't seem to be any DOM event letting us know about that event.
On my notebook Chrome does fire a non-standard orientationabsolutechange event, but I think not all notebooks have orientation aware hardware and already just Firefox on the same machine doesn't fire it.
But for what you want (an always up to date offset from an API served timestamp), you don't need a WebWorker at all, nor any timer, the computer comes with a good one and not only will it still be up to date after computer sleep, it will even be more precise than your interval which can suffer from time-drift.
All you need is to store the offset you got from your API and the computer's time you received it. Then you just need to get the difference between now and that time of reception and you can easily get your updated offset.
OP noted that they are afraid their users modify their computer's time to an earlier date, thus messing up with Date's values while the page is running. This can be detected. All it takes is to store the last value, and check if the difference with the current one is negative.
( async () => {
const offset_from_API = await getOffsetFromAPI();
const time_received = Date.now();
let last_time = time_received;
const getUpToDateOffset = () => {
const now = Date.now();
// Anti-Back-Time-Travelling check
// (it's a good idea to poll this method quite often too update `last_time`)
if( now - last_time < 0 ) {
throw new Error( 'cheater detected' );
}
last_time = now;
return offset_from_API + (now - time_received);
};
// to compare we will also use an incrementer
let incremented = offset_from_API;
setInterval( () => {
incremented += 1000;
console.clear();
console.log( 'incremented', incremented.toLocaleString( 'en-US' ) );
console.log( 'difference ', getUpToDateOffset().toLocaleString( 'en-US' ) );
}, 1000 );
} )();
function getOffsetFromAPI() { return 1234567; }
setInterval(() => {
/*handle userTimezoneTimestamp stuff every N miliseconds */
}, N);
setInterval(() => {
userTimezoneTimestamp = userTimezoneTimestamp + 1000
postMessage(userTimezoneTimestamp);
}, 1000);

Why is my node-oracledb execute Promise steadily increasing in the amount of time it takes to resolve?

I'm writing an ETL tool that interacts with an Oracle database which also uses node-oracledb 1.10 and RxJS to handle all of the various asynchronous data streams that I'm tossing around. I'm running into an issue where the longer my application runs, the longer a call to node-oracledb's .execute() takes, and it seems to increase in running time linearly. Hopefully you can spot the mistake in the code below and correct it.
First let me show how I'm running Oracle queries. I created my own .execute() function that acts as a wrapper around node-oracledb's .execute().
import oracledb from 'oracledb';
var oraConnPool;
export function execute(sql, bind, opts) {
if (!oraConnPool) {
createOraPool();
}
return oraConnPool
.then(pool => pool.getConnection())
.then(conn => conn.execute(sql, bind, opts));
}
function createOraPool() {
let oraPool = oracledb.createPool(config.database.oracle);
oraConnPool = oraPool;
return oraPool;
}
And my config.database.oracle (without the credentials):
{
"poolTimeout": 60,
"poolMin": 10,
"poolMax": 25,
"queueRequests": true,
"queueTimeout": 600000,
"_enableStats": true
}
Below is an example of me invoking my .execute() function. As you can see, there's a lot happening here, so let me try to annotate it a bit for clarity. rnd is used to create a unique id for console.time(), so I can keep track of the time it takes for the .execute() Promise to resolve. Let me know if there's a flaw in this time measuring technique. The bind input variable passed to the SELECT statement is a csv string of ssid identifiers, and a list of matches will be returned. This allows me to batch process records instead of creating a single query for each individual row, hopefully saving some execution time. The first .then() makes every key in the resulting array of objects lowercase. The second .then(), obviously, ends the console.time() tracking.
const rnd = Math.random() * 100;
console.time(rnd);
return execute(`
SELECT
ssid_input.ssid AS ssid,
students.id AS student_id,
students.student_number AS student_number
FROM (
SELECT REGEXP_SUBSTR(
:ssids,
'[^,]+', 1, level) AS ssid
FROM dual
CONNECT BY REGEXP_SUBSTR(
:ssids,
'[^,]+', 1, level) IS NOT NULL
) ssid_input
LEFT JOIN students ON students.state_studentnumber = ssid_input.ssid`, {
ssids: {
val: ssids.join(','),
dir: orawrap.BIND_IN,
type: orawrap.STRING
}
}, {
outFormat: orawrap.OBJECT,
maxRows: ssids.length
})
.then(results => {
return results.rows.map(result => {
let newObj = {};
Object.keys(result).forEach(key => {
newObj[key.toLowerCase()] = result[key];
});
return newObj;
});
})
.then(result => {
console.timeEnd(rnd);
return result;
});
Below is the console.time() output, which increases steadily until it hits the 60000 ms queueTimeout limit.
97.24179652744425: 12226.930ms
38.14057213652584: 14583.518ms
46.19793585774834: 16024.785ms
16.12600313565251: 17820.694ms
87.73720584788988: 20809.461ms
54.711100085462604: 22652.638ms
42.474404414891744: 24037.868ms
49.09845121453702: 26521.596ms
87.70258724764568: 29461.480ms
1.0731996619882223: 31210.875ms
90.33430329792829: 32259.944ms
37.4829457960367: 34076.824ms
9.731832830291932: 35292.281ms
/home/nathanjones/Projects/test-forge/node_modules/#reactivex/rxjs/dist/cjs/util/subscribeToResult.js:41
root_1.root.setTimeout(function () { throw err; });
^
Error: NJS-040: connection request timeout
I've tried to include most of the relevant code, please let me know if you need more context.
EDIT:
I added a console.log(pool._logStats()) statement every time the .execute() function is called. I've included the output of the last time it was printed before the NJS-040 error:
Pool statistics:
...total up time (milliseconds): 62823
...total connection requests: 1794
...total requests enqueued: 1769
...total requests dequeued: 0
...total requests failed: 0
...total request timeouts: 0
...max queue length: 1769
...sum of time in queue (milliseconds): 0
...min time in queue (milliseconds): 0
...max time in queue (milliseconds): 0
...avg time in queue (milliseconds): 0
...pool connections in use: 25
...pool connections open: 25
Related pool attributes:
...queueRequests: true
...queueTimeout (milliseconds): 60000
...poolMin: 10
...poolMax: 25
...poolIncrement: 1
...poolTimeout (seconds): 60
...stmtCacheSize: 30
Related environment variables:
...process.env.UV_THREADPOOL_SIZE: undefined
undefined
(This is a duplicate of node-oracledb Issue 474).
You need to make sure you close connections.
You probably need to increase UV_THREADPOOL_SIZE, see the node-oracledb documentation on Connections and Number of Threads.

how to find dynamic dom loaded time from server response in chrome? [duplicate]

I need to get execution time in milliseconds.
I originally asked this question back in 2008. The accepted answer then was to use new Date().getTime() However, we can all agree now that using the standard performance.now() API is more appropriate. I am therefore changing the accepted answer to this one.
Using performance.now():
var startTime = performance.now()
doSomething() // <---- measured code goes between startTime and endTime
var endTime = performance.now()
console.log(`Call to doSomething took ${endTime - startTime} milliseconds`)
In Node.js it is required to import the performance class
importing performance
const { performance } = require('perf_hooks');
Using console.time: (living standard)
console.time('doSomething')
doSomething() // <---- The function you're measuring time for
console.timeEnd('doSomething')
Note: The string being passed to the time() and timeEnd() methods must match(for the timer to finish as expected).
console.time() documentations:
MDN documentation
Node.js documentation
use new Date().getTime()
The getTime() method returns the number of milliseconds since midnight of January 1, 1970.
ex.
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
// do something
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
Don't use Date(). Read below.
Use performance.now():
<script>
var a = performance.now();
alert('do something...');
var b = performance.now();
alert('It took ' + (b - a) + ' ms.');
</script>
It works on:
IE 10 ++
FireFox 15 ++
Chrome 24 ++
Safari 8 ++
Opera 15 ++
Android 4.4 ++
etc, etc
console.time may be viable for you, but it's non-standard §:
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
Besides browser support, performance.now seems to have the potential to provide more accurate timings as it appears to be the bare-bones version of console.time.
<rant> Also, DON'T EVER use Date for anything because it's affected by changes in "system time". Which means we will get invalid results —like "negative timing"— when the user doesn't have an accurate system time:
On Oct 2014, my system clock went haywire and guess what.... I opened Gmail and saw all of my day's emails "sent 0 minutes ago". And I'd thought Gmail is supposed to be built by world-class engineers from Google.......
(Set your system clock to one year ago and go to Gmail so we can all have a good laugh. Perhaps someday we will have a Hall of Shame for JS Date.)
Google Spreadsheet's now() function also suffers from this problem.
The only time you'll be using Date is when you want to show the user his system clock time. Not when you want to get the time or to measure anything.
If you need to get function execution time on your local development machine, you can either use your browser's profiling tools, or console commands such as console.time() and console.timeEnd().
All modern browsers have JavaScript profilers built-in. These profilers should give the most accurate measurement as you do not have to modify your existing code, which could affect the function's execution time.
To profile your JavaScript:
In Chrome, press F12 and select the Profiles tab, then Collect JavaScript CPU Profile.
In Firefox, install/open Firebug, and click on the Profile button.
In IE 9+, press F12, click on Script or Profiler (depending on your version of IE).
Alternatively, on your development machine, you can add instrumentation to your code with console.time() and console.timeEnd(). These functions, supported in Firefox11+, Chrome2+ and IE11+, report on timers that you start/stop via console.time(). time() takes a user-defined timer name as an argument, and timeEnd() then reports on the execution time since the timer started:
function a() {
console.time("mytimer");
... do stuff ...
var dur = console.timeEnd("myTimer"); // NOTE: dur only works in FF
}
Note that only Firefox returns the elapsed time in the timeEnd() call. The other browsers simply report the result to the developer console: the return value of timeEnd() is undefined.
If you want to get function execution time in the wild, you will have to instrument your code. You have a couple options. You can simply save the start and end times by querying new Date().getTime():
function a() {
var start = new Date().getTime();
... do stuff ...
var end = new Date().getTime();
var dur = end - start;
}
However, the Date object only has millisecond resolution and will be affected by any OS's system clock changes. In modern browsers, there's a better option.
The better option is to use the High Resolution Time, aka window.performance.now(). now() is better than the traditional Date.getTime() in two important ways:
now() is a double with submillisecond resolution that represents the number of milliseconds since the start of the page's navigation. It returns the number of microseconds in the fractional (e.g. a value of 1000.123 is 1 second and 123 microseconds).
now() is monotonically increasing. This is important as Date.getTime() can possibly jump forward or even backward on subsequent calls. Notably, if the OS's system time is updated (e.g. atomic clock synchronization), Date.getTime() is also updated. now() is guaranteed to always be monotonically increasing, so it is not affected by the OS's system time -- it will always be wall-clock time (assuming your wall clock is not atomic...).
now() can be used in almost every place that new Date().getTime(), + new Date andt Date.now() are. The exception is that Date and now() times don't mix, as Date is based on unix-epoch (the number of milliseconds since 1970), while now() is the number of milliseconds since your page navigation started (so it will be much smaller than Date).
Here's an example of how to use now():
function a() {
var start = window.performance.now();
... do stuff ...
var end = window.performance.now();
var dur = end - start;
}
now() is supported in Chrome stable, Firefox 15+, and IE10. There are also several polyfills available.
One other option for measuring execution time in the wild is UserTiming. UserTiming behaves similarly to console.time() and console.timeEnd(), but it utilizes the same High Resolution Timestamp that now() uses (so you get a sub-millisecond monotonically increasing clock), and saves the timestamps and durations to the PerformanceTimeline.
UserTiming has the concepts of marks (timestamps) and measures (durations). You can define as many of either as you want, and they're exposed on the PerformanceTimeline.
To save a timestamp, you call mark(startMarkName). To get the duration since your first mark, you simply call measure(measurename, startMarkname). The duration is then saved in the PerformanceTimeline alongside your marks.
function a() {
window.performance.mark("start");
... do stuff ...
window.performance.measure("myfunctionduration", "start");
}
// duration is window.performance.getEntriesByName("myfunctionduration", "measure")[0];
UserTiming is available in IE10+ and Chrome25+. There is also a polyfill available (which I wrote).
To get precise values you should use Performance interface. It's supported in modern versions of Firefox, Chrome, Opera and IE. Here's an example of how it can be used:
var performance = window.performance;
var t0 = performance.now();
doWork();
var t1 = performance.now();
console.log("Call to doWork took " + (t1 - t0) + " milliseconds.")
Date.getTime() or console.time() are not good for measuring precise execution time. You can use them if quick rough estimate is OK for you. By rough estimate I mean you can get 15-60 ms shift from the real time.
Check this brilliant post on measuring execution time in JavaScript. The author also gives a couple of links about accuracy of JavaScript time, worth reading.
Use Firebug, enable both Console and Javascript. Click Profile. Reload. Click Profile again. View the report.
A simple solution, you can use add operator also here
var start = +new Date();
callYourFunctionHere();
var end = +new Date();
var time = end - start;
console.log('total execution time = '+ time + 'ms');
process.hrtime() is available within Node.js - it returns a value in nanoseconds
let hrTime = process.hrtime()
console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)
Here's a decorator for timing functions
It wraps functions so that they get timed each time they get run
Usage:
let test = () => { /* does something */ }
test = timed(test) // turns the function into a timed function in one line
test() // run your code as normal, logs 'function test took 1001.900ms'
This is the decorator:
let timed = (f) => (...args) => {
let start = performance.now();
let ret = f(...args);
console.log(`function ${f.name} took ${(performance.now() - start).toFixed(3)}ms`);
return ret;
}
If you're using async functions you can make timed async and add an await before f(...args), and that should work for those. It gets more complicated if you want one decorator to handle both sync and async functions.
var StopWatch = function (performance) {
this.startTime = 0;
this.stopTime = 0;
this.running = false;
this.performance = performance === false ? false : !!window.performance;
};
StopWatch.prototype.currentTime = function () {
return this.performance ? window.performance.now() : new Date().getTime();
};
StopWatch.prototype.start = function () {
this.startTime = this.currentTime();
this.running = true;
};
StopWatch.prototype.stop = function () {
this.stopTime = this.currentTime();
this.running = false;
};
StopWatch.prototype.getElapsedMilliseconds = function () {
if (this.running) {
this.stopTime = this.currentTime();
}
return this.stopTime - this.startTime;
};
StopWatch.prototype.getElapsedSeconds = function () {
return this.getElapsedMilliseconds() / 1000;
};
StopWatch.prototype.printElapsed = function (name) {
var currentName = name || 'Elapsed:';
console.log(currentName, '[' + this.getElapsedMilliseconds() + 'ms]', '[' + this.getElapsedSeconds() + 's]');
};
Benchmark
var stopwatch = new StopWatch();
stopwatch.start();
for (var index = 0; index < 100; index++) {
stopwatch.printElapsed('Instance[' + index + ']');
}
stopwatch.stop();
stopwatch.printElapsed();
Output
Instance[0] [0ms] [0s]
Instance[1] [2.999999967869371ms] [0.002999999967869371s]
Instance[2] [2.999999967869371ms] [0.002999999967869371s]
/* ... */
Instance[99] [10.999999998603016ms] [0.010999999998603016s]
Elapsed: [10.999999998603016ms] [0.010999999998603016s]
performance.now() is optional - just pass false into StopWatch constructor function.
It is possible to use only one variable:
var timer = -performance.now();
// Do something
timer += performance.now();
console.log("Time: " + (timer/1000).toFixed(5) + " sec.")
timer/1000 - to convert milliseconds to seconds
.toFixed(5) - to trim extra digits
To extend vsync's code further to have the ability to return the timeEnd as a value in NodeJS use this little piece of code.
console.timeEndValue = function(label) { // Add console.timeEndValue, to add a return value
var time = this._times[label];
if (!time) {
throw new Error('No such label: ' + label);
}
var duration = Date.now() - time;
return duration;
};
Now use the code like so:
console.time('someFunction timer');
someFunction();
var executionTime = console.timeEndValue('someFunction timer');
console.log("The execution time is " + executionTime);
This gives you more possibilities. You can store the execution time to be used for more purposes like using it in equations, or stored in a database, sent to a remote client over websockets, served on a webpage, etc.
there are multiple ways to achieve this objective :
using console.time
console.time('function');
//run the function in between these two lines for that you need to
//measure time taken by the function. ("ex. function();")
console.timeEnd('function');
this is the most efficient way :
using performance.now(), e.g.
var v1 = performance.now();
//run the function here for which you have top measure the time
var v2 = performance.now();
console.log("total time taken = "+(v2-v1)+"milliseconds");
use +(add operator) or getTime()
var h2 = +new Date(); //or
var h2 = new Date().getTime();
for(i=0;i<500;i++) { /* do something */}
var h3 = +new Date(); //or
var h3 = new Date().getTime();
var timeTaken = h3-h2;
console.log("time ====", timeTaken);
Here's what happens when you apply the unary plus operator to a Date instance:
Get the value of the Date instance in question
Convert it to a Number
NOTE: getTime() gives better performance than unary + operator.
It may help you.
var t0 = date.now();
doSomething();
var t1 = date.now();
console.log("Call to doSomething took approximate" + (t1 - t0)/1000 + " seconds.")
This is a Timer function. If you want to measure the time between multiple things that aren't nested:
function timer(lap){
if(lap) console.log(`${lap} in: ${(performance.now()-timer.prev).toFixed(3)}ms`);
timer.prev = performance.now();
}
Similar to console.time(), but easier usage if you don't need to keep track of previous timers.
Usage:
timer() // set the start
// do something
timer('built') // logs 'built in: 591.815ms'
// do something
timer('copied') // logs 'copied in: 0.065ms'
// do something
timer('compared') // logs 'compared in: 36.41ms'
If you like the blue color from console.time(), you can use this line instead
console.log(`${lap} in: %c${(performance.now()-timer.prev).toFixed(3)}ms`, 'color:blue');
Since console.time and performance.now aren't supported in some major browsers (i.e. IE10), I created a slim utility that utilizes the best available methods. However, it lacks error handling for false usages (calling End() on a not initialized timer).
Use it and improve it as you want.
Performance: {
Timer: {},
Start: function (name) {
if (console && console.time) {
console.time(name);
} else if (window.performance.now) {
this.Timer[name] = window.performance.now();
} else {
this.Timer[name] = new Date().getTime();
}
},
End: function (name) {
if (console && console.time) {
console.timeEnd(name);
} else {
var result;
if (window.performance.now) {
result = window.performance.now() - this.Timer[name];
} else {
result = new Date().getTime() - this.Timer[name];
}
console.log(name + ": " + result);
}
}
}
Use this code format
const startTime =new Date().getTime();
//do something
const endTime = new Date().getTime();
console.log(`time taken ${(endTime - startTime)/1000} seconds`);
A couple months ago I put together my own routine that times a function using Date.now() -- even though at the time the accepted method seemed to be performance.now() --
because the performance object is not yet available (built-in) in the stable Node.js release.
Today I was doing some more research and found another method for timing. Since I also found how to use this in Node.js code, I thought I would share it here.
The following is combined from the examples given by w3c and Node.js:
function functionTimer() {
performance.mark('start')
functionToBeTimed()
performance.mark('end')
performance.measure('Start to End', 'start', 'end')
const measure = performance.getEntriesByName('Start to End')[0]
console.log(measure.duration)
}
NOTE:
If you intend to use the performance object in a Node.js app, you must include the following require:
const { performance } = require('perf_hooks')
Thanks, Achim Koellner, will expand your answer a bit:
var t0 = process.hrtime();
//Start of code to measure
//End of code
var timeInMilliseconds = process.hrtime(t0)[1]/1000000; // dividing by 1000000 gives milliseconds from nanoseconds
Please, note, that you shouldn't do anything apart from what you want to measure (for example, console.log will also take time to execute and will affect performance tests).
Note, that in order by measure asynchronous functions execution time, you should insert var timeInMilliseconds = process.hrtime(t0)[1]/1000000; inside the callback. For example,
var t0 = process.hrtime();
someAsyncFunction(function(err, results) {
var timeInMilliseconds = process.hrtime(t0)[1]/1000000;
});
With performance
NodeJs: It is required to import the performance class
var time0 = performance.now(); // Store the time at this point into time0
yourFunction(); // The function you're measuring time for
var time1 = performance.now(); // Store the time at this point into time1
console.log("youFunction took " + (time1 - time0) + " milliseconds to execute");
Using console.time
console.time('someFunction');
someFunction(); // Whatever is timed goes between the two "console.time"
console.timeEnd('someFunction');
Use console.time('some label here') before the function and console.timeEnd('some label here') after the function. It will give you the running time of the function.
Stopwatch with cumulative cycles
Works with server and client (Node or DOM), uses the Performance API.
Good when you have many small cycles e.g. in a function called 1000 times that processes 1000 data objects but you want to see how each operation in this function adds up to the total.
So this one uses a module global (singleton) timer. Same as a class singleton pattern, just a bit simpler to use, but you need to put this in a separate e.g. stopwatch.js file.
const perf = typeof performance !== "undefined" ? performance : require('perf_hooks').performance;
const DIGITS = 2;
let _timers = {};
const _log = (label, delta?) => {
if (_timers[label]) {
console.log(`${label}: ` + (delta ? `${delta.toFixed(DIGITS)} ms last, ` : '') +
`${_timers[label].total.toFixed(DIGITS)} ms total, ${_timers[label].cycles} cycles`);
}
};
export const Stopwatch = {
start(label) {
const now = perf.now();
if (_timers[label]) {
if (!_timers[label].started) {
_timers[label].started = now;
}
} else {
_timers[label] = {
started: now,
total: 0,
cycles: 0
};
}
},
/** Returns total elapsed milliseconds, or null if stopwatch doesn't exist. */
stop(label, log = false) {
const now = perf.now();
if (_timers[label]) {
let delta;
if(_timers[label].started) {
delta = now - _timers[label].started;
_timers[label].started = null;
_timers[label].total += delta;
_timers[label].cycles++;
}
log && _log(label, delta);
return _timers[label].total;
} else {
return null;
}
},
/** Logs total time */
log: _log,
delete(label) {
delete _timers[label];
}
};
The best way would be to use the performance hooks module. Although unstable, you can mark specific areas of your code and measure the duration between marked areas.
const { performance, PerformanceObserver } = require('perf_hooks');
const measures = []
const obs = new PerformanceObserver(list => measures.push(...list.getEntries()));
obs.observe({ entryTypes: ['measure'] });
const getEntriesByType = cb => cb(measures);
const doSomething = val => {
performance.mark('beginning of the process');
val *= 2;
performance.mark('after multiplication');
performance.measure('time taken', 'beginning of the process', 'after multiplication');
getEntriesByType(entries => {
entries.forEach(entry => console.log(entry));
})
return val;
}
doSomething(4);
Try here
export default class Singleton {
static myInstance: Singleton = null;
_timers: any = {};
/**
* #returns {Singleton}
*/
static getInstance() {
if (Singleton.myInstance == null) {
Singleton.myInstance = new Singleton();
}
return this.myInstance;
}
initTime(label: string) {
this._timers[label] = Date.now();
return this._timers[label];
}
endTime(label: string) {
const endTime = Date.now();
if (this._timers[label]) {
const delta = endTime - this._timers[label];
const finalTime = `${label}: ${delta}ms`;
delete this._timers[label];
return finalTime;
} else {
return null;
}
}
}
InitTime related to string.
return Singleton.getInstance().initTime(label); // Returns the time init
return Singleton.getInstance().endTime(label); // Returns the total time between init and end
In my case, I perfer to use # grammar suger and compile it with babel.
The problem of this method is that function has to be inside object.
Sample JS Code
function timer() {
return (target, propertyKey, descriptor) => {
const start = Date.now();
let oldFunc = descriptor.value;
descriptor.value = async function (){
var result = await oldFunc.apply(this, arguments);
console.log(Date.now() - start);
return result;
}
}
}
// Util function
function delay(timeout) {
return new Promise((resolve) => setTimeout(() => {
resolve();
}, timeout));
}
class Test {
#timer()
async test(timout) {
await delay(timout)
console.log("delay 1");
await delay(timout)
console.log("delay 2");
}
}
const t = new Test();
t.test(1000)
t.test(100)
.babelrc (for babel 6)
{
"plugins": [
"transform-decorators-legacy"
]
}
To start the timer use console.time("myTimer");
Optional: To print the elapsed time, use
console.timeLog("myTimer");
Finally, to stop the timer and print the final
time: console.timeEnd("myTimer");
You can read more about this on MDN and in the Node.js documentation.
Available on Chrome, Firefox, Opera and NodeJS. (not on Edge or Internet Explorer).
Note: Simplest implementation of pure functional, ES6 method, no extra variables needed, just 3 lines of codes. Handles sync and async codes, so no external libraries needed, works in both JavaScript and Node JS, can even use to test the latency of your APIs
// Create one-liner timer function
let [timer, timingMonitor] = [0, () => timer = !timer ? Date.now() : `${Date.now() - timer}ms`]
// Initiate timer
timingMonitor();
// Your code here
doSomething();
// End timer
console.log(timingMonitor());
// Console output: "102ms", for example
Basic TypeScript example that supports marks. Calling start('something') will begin the timer and stop('something') will end the timer and return a formatted string containing elapsed time.
View Flems Example
/**
* Mark entries
*/
export const marks: { [id: string]: number } = {};
/**
* Start timing
*/
export const start = (id: string) => {
return Object.assign(marks, {[id]: Date.now() })[id]
}
/**
* Clear all
*/
export const clear = () => {
for (const id in marks) delete marks[id];
};
/**
* Stop timing and return formatted elapsed time
*/
export const stop = (id: string) => {
const ms = Date.now() - marks[id];
delete marks[id];
return ms > 1000
? `${(ms / 1000).toFixed(0)}s ${+ms.toFixed(0).slice(1)}ms`
: `${ms.toFixed(0)}ms`;
};
The example code is exporting each function. You can drop this into a project and call the methods accordingly from a default as import, eg:
import * as time from './timer.js'
time.start('foo')
// do something
console.log('elapsed time: ' + time.stop('bar'))
As previously stated check for and use built in timer. But if you want or need to write your own here is my two cents:
//=-=|Source|=-=//
/**
* JavaScript Timer Object
*
* var now=timer['elapsed']();
* timer['stop']();
* timer['start']();
* timer['reset']();
*
* #expose
* #method timer
* #return {number}
*/
timer=function(){
var a=Date.now();
b=0;
return{
/** #expose */
elapsed:function(){return b=Date.now()-a},
start:function(){return a=Date.now()},
stop:function(){return Date.now()},
reset:function(){return a=0}
}
}();
//=-=|Google Advanced Optimized|=-=//
timer=function(){var a=Date.now();b=0;return{a:function(){return b=Date.now()-a},start:function(){return a=Date.now()},stop:function(){return Date.now()},reset:function(){return a=0}}}();
Compilation was a success!
Original Size: 219 bytes gzipped (405 bytes uncompressed)
Compiled Size: 109 bytes gzipped (187 bytes uncompressed)
Saved 50.23% off the gzipped size (53.83% without gzip
The accepted answer is wrong !
Since JavaScript is asynchronous, the values of the variable end of the accepted answer would be wrong.
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
// JavaScript is not waiting until the for is finished !!
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
The execution of the for may be very fast so you can not see that the result is wrong. You can test it with a code doing some request :
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
$.ajax({
url: 'www.oneOfYourWebsites.com',
success: function(){
console.log("success");
}
});
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
So the alert will prompt very quickly but in the console you'll see that the ajax requests are continuing.
Here is how you should do it : https://developer.mozilla.org/en-US/docs/Web/API/Performance.now

Categories

Resources