Sleep in Node.js - javascript

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))
})

Related

What is the best way to handle function interrupts in javascript

Basically I have two async functions. One of them is a simple 5 second timeout and the other is a complicated async function with multiple steps.
Here is an example
const delay = ms => new Promise(res => setTimeout(res, ms));
class Runner {
async start() {
let printStuff = async () => {
for(let i = 0 ; i < 50; i++){
console.log(i);
await delay(50);
}
}
let printLetters = new Promise(async function(resolve, reject) {
const length = Math.floor(Math.random() * 10)
//dont know how long this will take
for(let i = 0; i < length; i++){
await printStuff();
}
resolve('letters');
});
let timeout = new Promise(async function(resolve, reject) {
await delay(5000);
resolve('timeout')
});
const finished = await Promise.all([timeout, printLetters]);
if(finished === 'timeout'){
this.stop();
}
}
stop(){
//stop printing stuff instantly
}
}
const myRunner = new Runner();
myRunner.start();
//could call myRunner.stop(); if the user canceled it
The way I would implement this would add a global variable and include an if statement inside the for loop to check if the interrupt has been called but I am wondering if there is a better way to implement this. An issue with this solution would be it would print a few more numbers. I would have to add another check to the other for loop and this could get messy quickly.
Here is a simple demo that uses my own library.
import { CPromise } from "c-promise2";
const task = CPromise.promisify(function* () {
let printStuff = CPromise.promisify(function* () {
for (let i = 0; i < 10; i++) {
console.log(i);
yield CPromise.delay(100);
}
});
const length = Math.floor(Math.random() * 10) + 3;
//dont know how long this will take
for (let i = 0; i < length; i++) {
yield printStuff();
}
return "letters";
});
const promise = task()
.timeout(5000)
.then(
(result) => console.log(`Done: ${result}`),
(err) => console.warn(`Fail: ${err}`)
);
setTimeout(() => {
promise.cancel();
}, 2000);
Is this what you're after?
What changed:
Promise.all replaced with Promise.race
added isStopped prop which makes the "complicated async function with multiple steps" skip execution for the remaining steps. it doesn't kill it, though. Promises are not cancelable.
const delay = ms => new Promise(res => setTimeout(res, ms));
class Runner {
isStopped = false;
async start() {
const printStuff = async () => {
let i = 0;
while (!this.isStopped) {
console.log(i++);
await delay(50);
}
}
const printLetters = new Promise(
resolve => printStuff()
.then(() => resolve('letters'))
);
const timeout = new Promise(
resolve => delay(5000)
.then(() => resolve('timeout'))
);
const finished = await Promise.race([timeout, printLetters]);
console.log({ finished });
if (finished === 'timeout') {
this.stop();
}
}
stop() {
this.isStopped = true;
}
}
const myRunner = new Runner();
myRunner.start();
<button onclick="myRunner.stop()">stop</button>
Initial answer (left it in as the comments reference it, not what's above; and in case someone finds it useful in 2074):
Here's an example outlining what I was suggesting in the comment. run() below returns a race between a rejector happening after 1s and a fulfiller which resolves in random time between 0 and 2s.
const rejector = (timeout) => new Promise((resolve, reject) => {
setTimeout(reject, timeout, 'rejected')
});
class Runner {
run() {
return Promise.race([
rejector(1000),
new Promise((resolve, reject) => {
setTimeout(resolve, Math.random() * 2000, 'fulfilled')
})
])
}
}
const t0 = performance.now();
[...Array(6).fill()].forEach((_, key) => {
const runner = new Runner();
runner.run()
.then(r => console.log(`Proomise ${key} ${r} after ${performance.now() - t0}ms`))
.catch(err => console.log(`Promise ${key} ${err} after ${performance.now() - t0}ms`));
})
Note: initially I placed the rejector inside the class but (at least for the above example) I don't see why it should not stay outside (in a real case scenario, imported from a helper file).
If you require an instantaneous stop capability, you would probably want to execute the print job as a external script. Then you use child processes like this.
const { spawn } = require('child_process');
class Runner {
......
start() {
this.job[somejobId] = spawn('command to execute script');
//this can be anything, including a node script, e.g. `node start.js`
.....
}
stop(jobId) {
if (jobId) {
//this will kill the script that you spawn above
this.job[jobId].kill('SIGHUP');
}
}
stopAllJobs() {
// looping through the job queue to kill all the jobs
this.job.forEach(job => job.kill('SIGHUP'))
}
}
You will have more info on how to start a child process from the node doc website https://nodejs.org/api/child_process.html#subprocesskillsignal
If your job (external script) is stalling, it's recommended that you only use the above codes if you have a minimum 2 CPU core, else it will affect your main process if your script is heavy.

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.

Why javascript promise doesn't async in for loop? [duplicate]

This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 3 years ago.
I have code like this:
const loop1 = length => new Promise((resolve, reject) => {
try {
let b = 0
for (let i = 0; i < length; i++) b = b + i
resolve(b)
} catch (e) {
reject(e)
}
})
const loop2 = length => new Promise((resolve, reject) => {
try {
let b = 0
for (let i = 0; i < length; i++) b = b + i
resolve(b)
} catch (e) {
reject(e)
}
})
const startTime = new Date().getTime()
loop1(10000000000).then(result => {
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log(`loop1: ${duration}`, result)
}).catch(error => console.log('loop1 error:', error))
loop2(1).then(result => {
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log(`loop2: ${duration}`, result)
}).catch(error => console.log('loop2 error:', error))
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log('duration', duration)
Why are the results like this?:
root#ububtu:~$ node .
duration 15539
loop1: 15545 49999999990067860000
loop2: 15545 0
Why isn't the result like this?:
root#ububtu:~$ node .
duration 0
loop2: 5 0
loop1: 15545 49999999990067860000
Why should wait loop1 for give the result?
Why not passed loop1 to give result loop2 first?
And why the duration time is not < 1 seconds but more than 15 seconds?
The function you pass into the Promise constructor (the promise executor function) is called synchronously. That's so that it can start the asynchronous process (whatever it is) that the promise represents.
So in your code, loop1's executor function runs synchronously, then the promise is returned, then loop2's executor function is run synchronously; later, the fulfillment handlers are called asynchronously.
Remember: Promises don't turn a synchronous thing into an asynchronous thing. They just provide a standardized means of observing the results of things that are already asynchronous.
If you update your code to model asynchronous operations (in this case I'll use setTimeout), you'll see loop2's handler called before loop1's, since it fulfills earlier:
const loop1 = length => new Promise((resolve) => {
setTimeout(resolve, length, length)
})
const loop2 = length => new Promise((resolve) => {
setTimeout(resolve, length, length)
})
const startTime = new Date().getTime()
loop1(800).then(result => {
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log(`loop1: ${duration}`, result)
}).catch(error => console.log('loop1 error:', error))
loop2(1).then(result => {
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log(`loop2: ${duration}`, result)
}).catch(error => console.log('loop2 error:', error))
const endTime = new Date().getTime()
const duration = endTime - startTime
console.log('duration', duration)

Strange behaviour with Promise.all

I have this code snippet that should await 5 promises, pause for 2 seconds and then continue to await another 5. However, the output shows that the two Promise.all are not awaited although when I tried to return a value in the promise it returns properly. Am I understanding the concept of Promise.all wrong or there is something missing in my code?
(function () {
let val = 0
const promiseArr = []
for (let i = 0; i < 10; i++) {
promiseArr[i] = new Promise((res) => {
val += 500
setTimeout((val2) => {
console.log(val2)
res()
}, val, val)
})
}
console.log();
(async function() {
await Promise.all(promiseArr.slice(0, 5))
console.log('start await')
await new Promise((res) => setTimeout(res, 2000))
console.log('done await')
await Promise.all(promiseArr.slice(6, 10))
})()
}) ()
Expected output:
500
...
2500
start await
done await
3000
...
5000
Actual output:
500
1000
1500
2000
2500
start await
3000
3500
4000
4500
done await
5000
EDIT:
Now I understand why it behaves like that. Looks like I misunderstood a fundamental concept with Promises. Thanks for you guys help!
You're seeing this because the promises begin running as soon as they are created (or, well, as soon as the current synchronous block finishes anyway), not when they are awaited upon.
Instrumenting and reorganizing your code a little, to print timestamps for each event might illuminate things:
const t0 = +new Date();
const logWithTime = (message = "") =>
console.log("" + Math.round(+new Date() - t0) + ": " + message);
(async function() {
let val = 0;
const resolver = res => {
val += 500;
const thisVal = val; // so we have a binding for the effective value
logWithTime("Creating timeout for " + thisVal);
setTimeout(
arg => {
logWithTime("Timeout for " + thisVal);
res();
},
thisVal,
thisVal,
);
};
const promiseArr = [];
for (let i = 0; i < 10; i++) {
promiseArr[i] = new Promise(resolver);
}
logWithTime("awaiting for first 5...");
await Promise.all(promiseArr.slice(0, 5));
logWithTime("waiting for 2 seconds...");
await new Promise(res => setTimeout(res, 2000));
logWithTime("waiting for the rest...");
await Promise.all(promiseArr.slice(6, 10));
logWithTime("all done");
})();
prints
0: Creating timeout for 500
10: Creating timeout for 1000
10: Creating timeout for 1500
10: Creating timeout for 2000
10: Creating timeout for 2500
10: Creating timeout for 3000
10: Creating timeout for 3500
10: Creating timeout for 4000
10: Creating timeout for 4500
10: Creating timeout for 5000
10: awaiting for first 5...
511: Timeout for 500
1011: Timeout for 1000
1515: Timeout for 1500
2013: Timeout for 2000
2510: Timeout for 2500
2511: waiting for 2 seconds...
3010: Timeout for 3000
3512: Timeout for 3500
4011: Timeout for 4000
4511: Timeout for 4500
4511: waiting for the rest...
5011: Timeout for 5000
5011: all done
(or thereabouts, depending on things).
You can see the order in which the timeouts get resolved there.
Your timers start ticking when you call setTimeout, not when you await the promise that is resolved by them.
While (res) => setTimeout(res, 2000) runs, you have 4 prior setTimeouts which finish and call console.log before resolving.
I stumbled on this misunderstanding myself too: when you define a Promise, it's function is executed in that moment. If I understand what you're trying to do, you need to define an array of functions, and call them as needed.
(function () {
let val = 0
const promiseArr = []
for (let i = 0; i < 10; i++) {
promiseArr[i] = () => new Promise((res) => {
val += 500
setTimeout((val2) => {
console.log(val2)
res()
}, val, val)
})
}
console.log();
(async function() {
await Promise.all(promiseArr.slice(0, 5).map((fn) => fn()))
console.log('start await')
await new Promise((res) => setTimeout(res, 2000))
console.log('done await')
await Promise.all(promiseArr.slice(6, 10).map((fn) => fn()))
})()
}) ()

Categories