Decorators in javascript - javascript

function debounce(f, ms) {
let isCool = false;
return function() {
if (!isCool) {
f.apply(this, arguments);
}
isCool = true;
setTimeout(() => isCool = false, ms);
};
}
let f = debounce(alert, 1000);
f(1); // runs immediately
f(2); // ignored
setTimeout(() => f(3), 100); // ignored ( only 100 ms passed )
setTimeout(() => f(4), 1100); // runs
setTimeout(() => f(5), 1500); // ignored (less than 1000 ms from the last run)
The result of debounce(f, ms) decorator should be a wrapper that passes the call to f at maximum once per ms milliseconds. When we call a “debounced” function, it guarantees that all future calls to the function made less than ms milliseconds after the previous call will be ignored.
Why my code doesn't working as it should be? It should ignore call to f(5), instead it runs...

#deceze's comment answers your question. I'll add that there's no reason to complicate matters with setTimeout. Simply track time between invocations.
function debounce(f, ms) {
let lastApply = 0;
const cooldownMs = ms;
return function() {
let now = Date.now();
if ((now - cooldownMs) >= lastApply) {
lastApply = now;
f.apply(this, arguments);
}
};
}
let f = debounce(console.log, 1000);
f(1); // runs immediately
f(2); // ignored
setTimeout(() => f(3), 100); // ignored ( only 100 ms passed )
setTimeout(() => f(4), 1100); // runs
setTimeout(() => f(5), 1500); // ignored (less than 1000 ms from the last run)

Related

Pause console output using Node.js

I am trying to create a time display (h:mm:ss) with just using the console and not on a web page. The time should be set initially and from there display the time as it changes.
When using the output console (in the web browser) or in vscode, is it possible for js or node.js, while printing thousands/multiple outputs to have a delay between each output being printed in the console without using an extension?
Here's an example of printing the current time to the console every 1 second:
// setInterval() executes the given function on a given time interval
setInterval(() => {
console.log(new Date().toTimeString()); // function to execute
}, 1000) // execute every 1000 ms
You can also print your own counter:
let secondsElapsed = 0
setInterval(() => {
console.log(`seconds elapsed = ${secondsElapsed}`);
secondsElapsed++;
}, 1000)
Here is how to accomplish what you seem to be asking:
const clockTick = (callback) => {
const tick = () => {
const now = Date.now();
callback(now);
setTimeout(tick, 1000 - (now % 1000));
}
tick();
}
clockTick(timestamp => {
const date = new Date(timestamp);
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
console.log(`${hours}:${minutes}:${seconds}`);
});
The accepted answer isn't correct. IMO, we should implement a queue or something similar in order to achieve "delay between each output". I find this question interesting so I implement this code for some fun (which use promise chain as a simple queue):
const callNext = (function () {
let queueChain = Promise.resolve();
// Called after previous command (1 second by default)
function callNext(func, delay = 1000) {
queueChain = queueChain.then(() => {
return new Promise((res) => {
setTimeout(() => {
func();
res();
}, delay);
});
});
}
return callNext;
})();
callNext(() => {
console.log('run after 3s')
}, 3000);
callNext(() => {
console.log('run after the above 3s')
}, 3000);
callNext(() => {
console.log('run after the above 1s by default')
});
we can create a simple logger using the above callNext for cleaner syntax:
const logger = (function () {
function createLogFn(name) {
return function (...args) {
let delay = 1000;
// take the last argument as "delay" param
if (typeof args[args.length -1] === 'number') {
delay = args.pop();
}
callNext(() => {
console[name](`${name.toUpperCase()} [${(new Date().toISOString())}]: `, ...args);
}, delay);
};
}
const logger = {
log: createLogFn('log'),
info: createLogFn('info'),
debug: createLogFn('debug'),
error: createLogFn('error'),
}
return logger;
})();
logger.log('run after 3s', 3000);
logger.log('run after the above 3s', 3000);
logger.log('run after the above 1s');
logger.info('final run after the above 2s', 2000);
Check it out: https://jsfiddle.net/pk5oqfxa/

How to measure the execution time of an asynchronous function in nodejs?

I'm trying to get the execution/response time of an asynchronous function that executes inside a node-fetch operation, like the following
async function getEditedData() {
var a = await fetch(`https://api.example.com/resorce_example`);
var b = await a.json();
// Some aditional treatment of the object obtained (b)
console.log("End of the asynchronous function")
}
I Used the library perf_hooks like this, but the execution time shows before
const hrtime = require ('perf_hooks').performance.now ;
var start = hrtime ();
getEditedData();
var end = hrtime ();
console.log (end - start);
I found the async_hooks library https://nodejs.org/api/perf_hooks.html#perf_hooks_measuring_the_duration_of_async_operations , but I can´t understand how it works. I am a basic in javascript/nodejs
You could simply store Date.now() in some variable and then check Date.now() when your Promise resolves (or rejects) and subtract to find the difference. For example:
const simulateSomeAsyncFunction = new Promise((resolve, reject) => {
console.log('Initiating some async process, please wait...')
const startTime = Date.now();
setTimeout(() => {
resolve(Date.now() - startTime);
}, 3000);
});
simulateSomeAsyncFunction.then(msElapsed => {
console.log(`Async function took ${msElapsed / 1000} seconds to complete.`);
});
Note: You could write code that achieves the same thing and appears to be synchronous by using await/async since that is just "syntactic sugar" built on top of Promises. For example:
const simulateSomeAsyncFunction = () => {
console.log('Initiating some async process, please wait...');
return new Promise((resolve, reject) => {
setTimeout(resolve, 3000);
});
};
// Await is required to be called within an async function so we have to wrap the calling code in an async IIFE
(async() => {
const startTime = Date.now();
await simulateSomeAsyncFunction();
const msElapsed = Date.now() - startTime;
console.log(`Async function took ${msElapsed / 1000} seconds to complete.`);
})();
Starting with a simple async function -
const fakeAsync = async (value) => {
const delay = 2000 + Math.random() * 3000 // 2 - 5 seconds
return new Promise(r => setTimeout(r, delay, value))
}
fakeAsync("foo").then(console.log)
console.log("please wait...")
// "please wait..."
// "foo"
We could write a generic function, timeit. This is a higher-order function that accepts a function as input and returns a new function as output. The new function operates like a decorated version of the original -
const timeit = (func = identity) => async (...args) => {
const t = Date.now()
const result = await func(...args)
return { duration: Date.now() - t, result }
}
// decorate the original
const timedFakeAsync = timeit(fakeAsync)
// call the decorated function
timedFakeAsync("hello").then(console.log)
timedFakeAsync("earth").then(console.log)
// { duration: 3614, result: "earth" }
// { duration: 4757, result: "hello" }
The timed version of our function returns an object, { duration, result }, that reports the runtime of our async function and the result.
Expand the snippet below to verify the results in your own browser -
const identity = x =>
x
const timeit = (func = identity) => async (...args) => {
const t = Date.now()
const result = await func(...args)
return { duration: Date.now() - t, result }
}
const fakeAsync = async (value) => {
const delay = 2000 + Math.random() * 3000 // 2 - 5 seconds
return new Promise(r => setTimeout(r, delay, value))
}
const timedFakeAsync = timeit(fakeAsync)
timedFakeAsync("hello").then(console.log)
timedFakeAsync("earth").then(console.log)
console.log("please wait...")
// "please wait..."
// { duration: 3614, result: "earth" }
// { duration: 4757, result: "hello" }
If you expect to set the end after getEditedData() is completed, you actually need to await getEditedData(). Otherwise, you'll go right past it while it executes... asynchrnously.

How to optimize a script in terms of performance

I have a function called ajaxCall() which simple does the call on a server and returns a value from a feed.
What I wanted to do is to save the value from feed to firstInterval variable, wait 10 seconds, make the call again and save the value to secondInterval variable. And then animate the increasing of these numbers on the webpage. This is what we have so far:
setInterval(function(){
getAmounts()
}, 11000);
function getAmounts(){
firstInterval = ajaxCall();
setTimeout(() => {
secondInterval = ajaxCall();
animateValue('#bronze-price p', firstInterval, secondInterval, 10000)
}, 10000);
};
function animateValue(id, start, end, duration) {
start = parseInt(start);
end = parseInt(end);
var range = end - start;
var current = start;
var increment = end > start? 1 : -1;
var stepTime = Math.abs(Math.floor(duration / range));
var obj = document.querySelector(id);
var timer = setInterval(function() {
current += increment;
obj.innerHTML = current;
if (current == end) {
clearInterval(timer);
}
}, stepTime);
}
So the idea is to have a function which gets first interval, after 10 seconds it grabs the second interval and calls the animation. This all is wrapped into setInterval function so I could change the number smoothly repeatedly.
However I am pretty sure that thats not a very clean solution since its setInterval in setTimeout and this all is wrapped in another setInterval function. I am also getting this kind of warnings in the console with both functions:
[Violation] 'setInterval' handler took ms
What would be the best approach to follow up on this idea but optimize the code?
I think Promises and requestAnimationFrame makes this a lot easier to handle while also getting rid of setTimeout/setInterval. An example would be:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#Getting_a_random_integer_between_two_values_inclusive
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// fake api endpoint
const ajaxCall = () => new Promise(resolve => {
setTimeout(resolve, 400, 1000 + getRandomIntInclusive(0, 1000));
});
// simple animation helper using requestAnimationFrame
const animate = (from, to, duration, cb) => {
const start = performance.now();
return new Promise(resolve => {
requestAnimationFrame(function loop() {
const f = (performance.now() - start) / duration;
cb(from + Math.round(f * (to - from)));
f < 1.0
? requestAnimationFrame(loop)
: resolve();
});
});
};
// main
(async (interval) => {
// where to output
const dst = document.querySelector('#out');
// initial value
let prev = 0;
// wait for next value of ajaxCall
while (true) {
const next = await ajaxCall();
console.log(`animating: ${prev} -> ${next}`);
// animate from `prev` to `next`
await animate(prev, next, interval, current => {
dst.innerHTML = current;
});
prev = next;
}
})(10000);
<div id="out"></div>

How to write a function "inOrder" that accepts two callbacks and invokes them in order.

How to Implement "inOrder" using the callback pattern and using Promises.
var logOne = setTimeout(function() {
console.log("one!");
}, Math.random() * 1000);
var logTwo = setTimeout(function() {
console.log("two!");
}, Math.random() * 1000);
inOrder(logOne, logTwo);
// one
// two
// it should always log those two in order regardless of their timing
Its impossible with setTimeout directly as you cant do delays etc. But you could create a wrapper that provides a few more options:
function timer(cb, ms) {
let start = +new Date;
let timeout = setTimeout(cb, ms);
return {
ms,
stop() {
if(!timeout) return;
clearTimeout(timeout);
ms -= (start - new Date);
timeout = null;
},
start() {
if(ms > 0 && !timeout) {
start = +new Date;
timeout = setTimeout(cb, ms);
}
},
delay(time) {
this.stop();
ms += time;
this.start();
}
};
}
So now it is quite easy:
function inOrder(a, b) {
if(a.ms > b.ms)
b.delay(a.ms - b.ms);
}
Usable as:
const one = timer(() => console.log("one"), 1000);
const two = timer(() => console.log("two"), 500);
inOrder(one, two);
Create two function logOne & logTwo and can resolve them using Promise.resolve
function logOne() {
setTimeout(function() {
console.log("one!");
}, Math.random() * 1000);
}
function logTwo() {
setTimeout(function() {
console.log("two!");
}, Math.random() * 5000);
}
function inOrder(a, b) {
Promise.resolve(a()).then(b())
}
inOrder(logOne, logTwo);
A friend of mine has asked me to help him with this one.
So first thing is you won't make it work unless you can use nodejs. In nodejs setTimeout returns Timer object, which (with a little hacky code) you can use to make it work.
Inside browser it's impossible without creating some kind of a wrapper around those functions. #Jonas Wilms has already showed it, so let me show you my hacky implementation:
var logOne = setTimeout(function () {
console.log('one!');
}, 5000);
var logTwo = setTimeout(function () {
console.log('two!');
}, 0);
function inOrder(logOne, logTwo) {
var logTwoCallback = logTwo._onTimeout;
clearTimeout(logTwo);
setTimeout(function checkTimeout() {
if (logOne._called) {
logTwoCallback();
} else {
setTimeout(checkTimeout, 0);
}
}, 0);
}
inOrder(logOne, logTwo);

Sleep in Node.js

Assumed that there is no "native" way to achieve this, my solution-like was
sleep = function(time) {
var stop = new Date().getTime();
while(new Date().getTime() < stop + time) {
;
}
return new Promise((r,_)=> r())
}
So doing sleep(1000*3).then(()=>console.log("awake")) it will sleep 3 seconds and then resolve the Promise:
(be aware that it will freeze this page one sec.)
sleep = function(time) {
var stop = new Date().getTime();
while (new Date().getTime() < stop + time) {;
}
return new Promise((r, _) => r())
}
console.log("sleeping...")
sleep(1000 * 1).then(() => console.log("awake"))
Assumed that this will run in the main thread it will freeze the main process so that doing
sleep(1000*1).then(()=>console.log("awake")); console.log("Hello")
it will result in a output
VM2628:1 Hello
VM2628:1 awake
at very end of the sleep. Of course doing
setTimeout(()=>sleep(1000*3).then(()=>console.log("awake")),1000);console.log("Hello")
VM2815:1 Hello
undefined
VM2815:1 awake
will make it async, but it does not address my need (to put to sleep my main process).
Any better way?
[UPDATE]
Promisified version
/**
* Sleep for time [msec]
* #param time int milliseconds
* #return Promise delayed resolve
* #usage
sleep(1000*3).then(()=>console.log("awake"))
*/
sleepP: function (time) {
return new Promise((resolve, reject) => {
var stop = new Date().getTime();
while (new Date().getTime() < stop + time) {
;
}
return resolve(true)
});
}
that can be called like
await sleepP( 1000 * 3 );
There is no need to freeze at all. Because of javascripts asynchronicity we can leave a part of the code for some time and resume later. At first we need a promising timer:
const timer = ms => new Promise( res => setTimeout(res, ms));
Then we can simply use it:
console.log("wait 3 seconds")
timer(3000).then(_=>console.log("done"));
Or with a bit syntactic sugar:
(async function(){
console.log("wait 3 seconds");
await timer(3000);
console.log("done");
})()
If you really want to freeze ( very bad ), you don't need promises at all:
function freeze(time) {
const stop = new Date().getTime() + time;
while(new Date().getTime() < stop);
}
console.log("freeze 3s");
freeze(3000);
console.log("done");
Since Node v15.0.0 there's a new way to sleep by using the Timers Promises API.
import {setTimeout} from 'timers/promises';
const bucket = ['a', 'b', 'c'];
for(const item of bucket) {
await getItem(item);
await setTimeout(100);
}
If you want to use also use the regular setTimeout timer you can alias the promise timer.
import {setTimeout as sleep} from 'timers/promises';
// promise `setTimeout` aliased as `sleep`
sleep(100).then(() => console.log('I waited'));
// regular callback `setTimeout` (scheduling timers)
setTimeout(() => console.log('I also waited'), 100);
function sleep(time, func){
if (typeof func === 'function'){
const timer = ms => new Promise( res => setTimeout(res, ms));
timer(time).then(i=>func());
}
else{
console.log('What about the function bro?')
}
}
sleep(1000, function(){
console.log('hello')
console.log('test')
var arr = [1,2,3,4]
arr.forEach(i => console.log(i))
})

Categories