Run function/code after certain time with nodejs - javascript

I am looking for a way to run some code in nodejs after N amount of seconds.
Tried setTimeout() but it seems to completely block on it until the time is out but this is not what I want since my server is still sending and receiving events.
Any advice?

Actually, setTimeout is asynchronous, so it will not block.
setTimeout(function(){
// this code will only run when time has ellapsed
}, n * 1000);
// this code will not block, and will only run at the time

Actually setTimeout() does exactly what you are asking for, it does not block and will execute the given function at some time in the future.
However, it can be tricky to understand what's going on in Node.js. I highly recommend making the investment in learning how to use the Promise API. It can be confusing at first, but gives you a very flexible structure for controlling ansynchronous events. Here is an example I wrote as part of learning how to use the Promise API. You will see that it actually uses setTimeout(), but embeds it in a Promise. Hopefully this code is self explanatory and helps you achieve what you need.
/*
* Try out javascript Promise code in Node.js
*
*/
"use strict";
function getRandomBoolean() {
return Math.random() > 0.5;
}
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
for (let i = 0; i < 5; i++) {
// Create a promise, which will randomly succeed (and call resolve) or
// fail (and call reject) after a random time interval
let intervalMS = getRandomInt(5000);
let promise = new Promise(function (resolve, reject) {
setTimeout(() => {
if (getRandomBoolean()) {
// Success - Call resolver function
resolve(i+" Hooray!");
} else {
// Treat this as an error - Call reject function
reject(i+" Sorry!");
}
}, intervalMS);
});
// When the promise is complete, show the results
promise.then(
// The first function is the resolve function, to be called
// with a result param upon successful completion of async task
result => console.log("Success: "+result),
// Next is reject function, to be called with an error parameter when something failed
error => console.log("Failure: "+error)
);
// Flow of execution falls through to here without blocking
console.log ("Created promise "+i+", will complete in "+intervalMS+" ms");
}
If you run the above example in Node.js (or actually it should run in the browser too, I just haven't tested it there) you will see output something like the following:
Created promise 0, will complete in 853 ms
Created promise 1, will complete in 2388 ms
Created promise 2, will complete in 2738 ms
Created promise 3, will complete in 3053 ms
Created promise 4, will complete in 652 ms
Success: 4 Hooray!
Failure: 0 Sorry!
Failure: 1 Sorry!
Success: 2 Hooray!
Success: 3 Hooray!
Note that the "Created promise..." output comes out first, showing you that the execution falls through without blocking.

Related

Promise not waiting for my async code to execute [duplicate]

This question already has answers here:
Aren't promises just callbacks?
(11 answers)
Closed 29 days ago.
I'm just discovering Promises and I'm trying to wrap my head around them. The W3C website has a page dedicated to it, featuring the following code :
let myPromise = new Promise(function(myResolve, myReject) {
let x = 0;
// The producing code (this may take some time)
if (x == 0) {
myResolve("OK");
} else {
myReject("Error");
}
});
myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
I tried to make my own try at it, with the following code :
let p = new Promise(function test(resolve, reject){
// here is supposed to be where the async code takes place, according to the
// article.
let a = 0;
setTimeout(() => {a = Math.floor(Math.random()*6)}, "1000")
// ...however the condition triggers before the setTimeout takes place.
if(a >= 0) {
resolve(`Success ! a = ${a}`);
} else {
reject(`Failure ! a = ${a}`);
}
});
p.then(function logResult(result){
console.log(result);
})
So I figured that this should work :
let q = new Promise(function test(resolve, reject){
let a = 0;
setTimeout(() => {
a = Math.floor(Math.random()*6);
if(a >= 4) {
resolve(`Success ! a = ${a}`);
} else {
reject(`Failure ! a = ${a}`);
}
}, "1000")
});
q.then(function logResult(result){
console.log(result);
})
And it does work, but it's the setTimeout callbacks that handles everything, not the promise itself, and doing it without the promise works just as fine :
let a = 0;
setTimeout(() => {
a = Math.floor(Math.random() * 6);
if (a >= 4) {
console.log(`Success ! a = ${a}`);
} else {
console.log(`Failure ! a = ${a}`);
}
}, "1000")
So there's definitely something I don't understand about how Promises are supposed to handle async code or why they're useful altogether. I wish someone would explain it to me.
The whole point of promises is to allow some other code to be executed while waiting for a promise to resolve or reject.
In your code, however, no action takes time; therefore, you can do the same without promises.
The most common scenario for promises is something like this:
Show the user a progress dialog
Request some data from the backend
Once data is retrieved, process it
After data is processed, show it to a user
There will be a delay between steps 2 and 3 because an HTTP request will take some time naturally. Also, step 3 may take some time to process, and we don't want to block our code execution while waiting for it to complete. In this case, we wrap step 2 in a promise and use then to execute steps 3 and 4.
Please let me know if this helps.
Promises are used to handle operations which take longer than others. For example fetching something from a server. Since JavaScript is single-threaded, promises and callbacks are the answer for problems with long executing operations. If you would fetch something from a server synchronously (without a promise or callback), you wouldn't be capable to interact with your app in any other way (Click handlers wouldn't work.). It would block the main thread for the time when it fetches the data. Promises and callbacks are executing when there is nothing left to execute. Using promise to wrap callback function might be used to utilize async/await and .then() with it. It's in addition to prevent what's called - callback hell (a lot of callbacks nested in each other).

Async functions works weird with Promises

I am trying to understand the mechanism of async functions. I found some code on MDN docs MDN docs, made some modifications and... cannot fully understand how it works.
var resolveAfter2Seconds = function() {
console.log("starting slow promise");
return new Promise(resolve => {
setTimeout(function() {
resolve(20);
console.log("slow promise is done");
}, 6000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise");
return new Promise(resolve => {
setTimeout(function() {
resolve(10);
console.log("fast promise is done");
}, 4000);
});
};
var sequentialStart = async function() {
console.log('==SEQUENTIAL START==');
const slow = await resolveAfter2Seconds();
const fast = await resolveAfter1Second();
console.log(fast);
console.log('why?');
console.log(slow);
}
sequentialStart();
For now I know that if we run this code we will immediately receive '==SEQUENTIAL START==' on the console, then "starting slow promise" then we have a Promise with setTimeout which indicates that 'slow promise is done' will appear after 6 seconds and the resolve(20) callback will be kept in api container since execution stack will be empty.JS gives us 'starting fast promise' and after four seconds we get 'fast promise is done' and then immediately 10, 'why?', 20.
I do not understand: what happens in the background exactly - I know that resolve(20) is kept in api container and the rest of the code are executed, then resolve(10) is also kept in api container and when the execution stack is empty they are returned as the results of resolving their Promises.
But:
What with the timer? 10,why,20 appears long after their timeout passes - resolve 20 appears on the screen long after 6 seconds.
What with order? It seems like they (resolve20 and resolve 10) are ready to be executed and kept in memory until I use them - print them in console in this case? TIME APPEARING and ORDER
I am very determined to understand it correctly.
Perhaps this will help clear things up. Async-await is just syntactic sugar, so your sequentialStart function is the exact same thing as:
var sequentialStart = function() {
console.log('==SEQUENTIAL START==');
resolveAfter2Seconds().then(function(slow) {
resolveAfter1Second().then(function(fast) {
console.log(fast);
console.log('why?');
console.log(slow);
});
});
}
I know that resolve(20) is kept in api container and the rest of the code are executed, then resolve(10) is also kept in api container and when the execution stack is empty they are returned as the results of resolving their Promises
That's not what's happening when using async-await, what your code is doing is the following in this specific order:
Call resolveAfter2Seconds()
await it to resolve and then assign the resolved value to the constant slow
Call resolveAfter1Second()
await it to resolve and then assign the resolved value to the constant fast
Call console.log(fast), then console.log('why?'), then console.log(slow)
It seems like you're expecting the promises to resolve in parallel, as they would if you weren't using async-await but the whole purpose of async-await is to be able to write code with promises as if it was synchronous (i.e. blocking) code without creating a nested mess of then callbacks.

Robot framework promise handling

Is there a way in Robot Framework to run a javascript method that returns a promise and resolve that promise so I could get a result from it? I tried to achieve it in two ways. The first way was to run the Execute Javascript keyword and pass the function, then set wait for some time (with Sleep) and trying to resolve the promise (it already finished to execute in the browser).
The code I used looks like that:
${promise}= Execute Javascript return runAllTests();
Sleep 30sec
${result}= Set Variable return ${promise}.then(function(result) { return result; });
The result I got with this was just the promise object (I think)
{u'all': {}, u'_setSettlePromisesQueued': {}, u'_setBoundTo': {}, u'_settlePromiseAtPostResolution': {}, u'_isRejectionUnhandled': {}...
I do not paste it all because it's 3000+ characters long, but it's not what I expected for sure. Actually, the result is exactly the same no matter if I put there Sleep keyword or not.
The second way was to use Execute Async Javascript keyword (with modified timeout) and then trying to resolve it.
Set Selenium Timeout 30sec
${result}= Execute Async Javascript return runAllTests().then(function(result) { return result});
The function finished to execute in the browser window, but Robot seems not to care and after 30 seconds it reports TimeoutException with this message:
TimeoutException: Message: asynchronous script timeout: result was not received in 30 seconds
I tried to find another way, maybe some built-in mechanism to handle the promises, but I did not find anything like that. Is there any way to do that? I use Robot with Selenium2Library.
The solution for this is basically in the Selenium2Library documentation. All it takes to make it work is to use the callback function, for example:
Set Selenium Timeout 60sec
${result}= Execute Async Javascript
... var callback = arguments[arguments.length-1];
... runAllTests().then(function() { callback(1); }).catch(function() { callback(0); });
This will set the result to 1 or 0 (as a string, not integer), depending on what is returned by this function (resolved or rejected promise). I was confused by this callback used in this example but it's working.
Following keyword allows getting back the promise response or error message.
PS Execute Async Promise
[Arguments] ${promise} ${timeout}=${PS_MAX_WAIT} ${return_function}=${None} ${failure_marker}=UNEXPECTED_STATE
[Documentation] Wrapper calling a asynchronous JavaScript ${promise} and wait till max ${timeout}, if it's promise returns \ a success or failure.
...
... Failure case:
... - \ the error.message is catched and reported
...
... Success case:
... - When ${return_function} is None, the promise response will be returned directly (default)
... - Otherwise, an additional *then* chain step is added to modify / prepare promise response .
...
... Sample: If ${return_function} is _JSON.stringify(response)_ , a chain step _then( function(response) { return JSON.stringify(response); } )_ is added
[Tags] internal
Set Selenium Timeout ${timeout}
${promise_chain}= Set Variable If '${return_function}'!='${None}' ${promise}.then( function(response) { return ${return_function}; } ) ${promise}
${error_return}= Set Variable '${failure_marker} - ' + error.name + ' - ' + error.message
${result}= Execute Async Javascript var callback = arguments[arguments.length-1]; ${promise_chain}.then(function(response) { callback( response ); }).catch(function(error) { callback( ${error_return} ); });
Should Not Contain ${result} ${failure_marker} js call aborts with ${result} - ${promise_chain}
[Teardown] PS Set Delay and Timeout to Default
[Return] ${result}
Sample robot suite using this keyword see robot-framework_sample_promises.robot.
It interacts with sample page Promises tests, provided by JavaScript Promises: an Introduction

Add a delay or sleep to an array of promises in nodejs [duplicate]

This question already has answers here:
How to synchronize a sequence of promises?
(6 answers)
Closed 5 years ago.
I have a promise chain problem I have been grappling with. I make a call out to an external api that returns me data that I need to process and ingest into a mongo database. I am using nodejs and mongodb with express. Anyway, the calls to the api are working ok, the problem is that I am making tons of them at once. I want to slow them down, like make all the calls for one set. Wait a minute. Make all the calls for the next set. If this was a known amount of sets I would just promise chain them. I dont know how many sets there are so I am looping through them. I think the closure is the problem but cant work around it. on to the example code!
function readApi(carFactory){
var promise = new Promise(function(resolve, reject) {
// call out to api, get set of car data from factory1
console.log(carFactory);
if (true) {
console.log('resolved');
resolve("Stuff worked!"+carFactory);
}
else {
reject(Error("It broke"));
}
});
return promise;
}
function manager(){
//singular call
readApi("this is a singular test").then(returnedThing=>{
console.log(returnedThing); //Stuff worked! this is a singular test
});
let dynamicList = ["carFactory1", "carFactory2","carFactory3","carFactory..N"];
let readApiAction = [];
dynamicList.forEach(carIter=>{
readApiAction.push(readApi(carIter));
});
//ok so now I got an array of promise objects.
//I want to call the first one, wait 1 minute and then call the next one.
//originally I was calling promise.all, but there is no way to get at
//each promise to pause them out so this code is what I am looking to fix
let results= Promise.all(readApiAction);
results.then(data=>{
data.forEach(resolvedData=>{
console.log(resolvedData); //Stuff worked carFactory1, etc...
});
});
//singular call with timeout, this does not work, each one called at the same time
let readApiActionTimeouts = [];
dynamicList.forEach(carIter=>{
setTimeout(callingTimeout(carIter), 6000);
});
}
//just a function to call the promise in a timeout
//this fails with this - TypeError: "callback" argument must be a function
function callingTimeout(carIter){
readApi(carIter).then(returnedThing=>{
console.log("timeout version"+returnedThing);
});
}
A bit on theory. Native Promise.all just groups promises. They're still executed simultaneously (in async way, though, as all JS code, but along each other). This means that it will still congest the API and perform a lot of calls.
Another thing to note is that if you want to delay a promise, you have to delay its return value (e.g. resolve). In order to do so, you may use setTimeout INSIDE new Promise (just look below for more explanation).
Set timeout is asynchronous. It does not work as in other languages (it does not just pause execution). Setting fixed timeout in your code just caused to move ALL the executions by 6s. They still happened in parallel (in different ticks, though, but it's a small difference). Try e.g. generating different timeouts for each one in the loop - you'll notice that they're happening in a different time BUT! This is not a good solution for promisified code!
And now - time for practical answer!
If you use Bluebird, it has a special method to add delay or timeout to each promise. Without it, you would have to write a wrapper around Promise, e.g. resolving it after a particular amount of time and then use it with Promise.all.
First solution (bluebird):
function delayMyPromise(myPromise, myDelay);
return Promise.delay(myDelay).then(function() {
return myPromise;
});
});
and then in your code:
return Promise.all(delayMyPromise(promise1, 1000), delayMyPromise(promise2, 2000)); // Notice different delays, you may generate them programatically
Or even cooler, you can use Promise.map from Bluebird instead of Promise.all that has a special concurrency setting so you may force your promises to be executed in particular sequence, e.g. 2 at a time.
This is how I did it on my previous project :)
More here:
http://bluebirdjs.com/docs/api/promise.delay.html
http://bluebirdjs.com/docs/api/map.html
Pure native Promise implementation:
function delayMyPromise(myPromise, myDelay) {
return new Promise(function (resolve, reject) {
setTimeout(function() {
return resolve(myPromise);
}, myDelay);
});
}
I'd, however, heavily recommend first approach if you don't mind using Bluebird. It's like lodash for Promises and it's really fast :)
you get the error : TypeError: "callback" argument must be a function because your callingTimeout returns nothing and setTimeout needs a function as argument, this is how to fixe it :
let readApiActionTimeouts = [];
dynamicList.forEach(carIter=>{
callingTimeout(carIter)
});
your promise :
function readApi(carFactory){
var promise = new Promise(function(resolve, reject) {
//...
setTimeout(()=>{
resolve("Stuff worked!"+carFactory);
}, 6000);
//...
});
return promise;
}
You could use recursion for something like this.
When you call .forEach, each iteration happens immediately.
In the example below, doSomething is not called until the setTimeout occurs, which means each letter is printed 1 second apart.
let letters = ["a", "b", "c"];
function doSomething(arr) {
console.log(arr[0]);
if (arr.length > 1) {
setTimeout(() => doSomething(arr.slice(1)), 1000);
}
}
doSomething(letters);
Alternately, for your array of promises:
let promises = [
Promise.resolve("A"),
Promise.resolve("B"),
Promise.resolve("C"),
];
function doSomething(arr) {
arr[0].then((result) => {
console.log(result);
if (arr.length > 1) {
setTimeout(() => doSomething(arr.slice(1)), 1000);
}
})
}
doSomething(promises);

How can I keep `.then()` alive long enough for a polling function with native promises?

Summary: poll() functions with callbacks are available; I haven't found any using native promises. I've tried to adapt some without success. The problem I haven't solved yet is that when the first instance of the function called by setTimeout ends without any return, the .then() listening for it sees the termination as a false and a reject(). then() terminates and doesn't listen for later returns.
Question: How best to help the .then() function stick around for later returns with resolve() or reject()?
The rest of this post is detail. Read what helps.
Available poll functions: I like (https://stackoverflow.com/users/1249219/om-shankar) Om Shankar's response in Calling a function every 60 seconds. David Walsh's poll() is very similar (at https://davidwalsh.name/essential-javascript-functions). Both use callbacks and work well. I found
poll in javascript
which includes a poll() using bluebird-only promises.
Here's my attempt at implementing with native promises.
/**
* poll - checks repeatedly whether a condition exists. When the condition
* exists, returns a resolved standard promise. When it has checked
* long enough, returns a rejected standard promise.
* #param {function} fn - a caller-supplied synchronous function that
* detects a condition in the environment. Returns true if the
* condition exists; otherwise false.
* #param {number} timeout - maximum number of milliseconds
* the caller wants to check param fn();
* reject() the promise at the expiration of param timeout.
* #param {number} interval - minimum number of milliseconds between
* calls to param fn(); resolve() the promise when param fn() first
* reports true.
* #return {promise} - resolved when param fn() returns true;
* rejected if param timeout expires without param fn() returning true
*/
function poll(fn, timeout, interval) {
let endTime = Number(new Date()) + (timeout || 2000)
interval = interval || 250
return Promise.resolve *2
.then(() => { *3
(function p(fn, endTime, interval) {
if (fn()) { return Promise.resolve("Condition is satisfied.") } *4
else {
if (Number(new Date()) <= endTime) {) *5
window.setTimout(p, interval, fn, endTime, interval) *6
}
else {
return Promise.reject("Past endTime; condition not satisfied")
}
}
}()) *7
}) *8
}
Expected usage:
function waitIsOver() { return (<desired condition exists>) }
poll(waitIsOver, 2000, 250) *1
The way I think this is running (please correct me if I'm wrong): After the call to poll() at *1, we quickly return a pending promise at *2 so that poll() knows to wait. Then, we call that promise's then() function at *3. Function p() starts. If fn() (known outside p() as waitIsOver()) returns true at *4, we're good: We return resolve() and poll() at *1 gets the settled promise it seeks.
Then the bad part: If fn() returns false at *4 and we're inside endTime at *5 (which is likely; the first call is unlikely to occur after endTime), we use setTimeout() at *6 to ask JS to make a note in the stack to instantiate another p() after interval time. After that, the first instance of p() terminates at *7. At *8, then() knows that p() terminated without returning anything and interprets the condition as returning false and reject(); with reject(), the promise is settled and can never change. However, after expiration of interval, a successor instance of p() fires up. Anything it returns is lost; the promise is settled and then() has terminated after sending execution on an unwanted path.
How do I convert an existing callback API to promises? recommends an approach with a Promise constructor, resolve() calling callback(), and reject() calling errback. I tried the technique, but I ran into the same problem of the then() function ending before I want it to. I haven't yet figured out how to make then() as patient in waiting as a callback function.
That sets up the question. Again:
Question: How best to help the .then() function stick around for later returns from resolve() or reject()?
How best to help the .then() function stick around for later returns
from resolve() or reject()
A .then() handler is called when the underlying promise is resolved or rejected. It's not called before that, ever. So, if you want to delay when the .then() handler is called, then you delay resolving or rejecting the underlying promise until the appropriate time.
As you can tell from my comments, it is hard to tell exactly what you're trying to accomplish because you don't just describe a straightforward objective you are trying to accomplish.
Given that, here's my guess at what you're trying to accomplish. A clear question could have receive an answer like this in a few minutes.
If you just want to repeatedly poll your function until it returns a truthy value or until the timeout time hits, you can do this with standard ES6 promies:
function poll(fn, timeout, interval) {
return new Promise(function(resolve, reject) {
// set timeout timer
var timeoutTimer = setTimeout(function() {
clearInterval(intervalTimer);
reject("Past endTime; condition not satisfied");
}, timeout);
// set polling timer
var intervalTimer = setInterval(function() {
if (fn()) {
clearTimeout(timeoutTimer);
clearInterval(intervalTimer);
resolve("Condition is satisfied");
}
}, interval);
});
}
poll(yourFounction, 5000, 100).then(function(result) {
// succeeded here
}).catch(function(err) {
// timed out here
})
Or, with the Bluebird promise library, you can use its .timeout() method to do this:
function poll(fn, timeout, interval) {
return new Promise(function(resolve, reject) {
// set polling timer
var intervalTimer = setInterval(function() {
if (fn()) {
clearInterval(intervalTimer);
resolve("Condition is satisfied");
}
}, interval);
}).timeout(timeout, "Past endTime; condition not satisfied");
}
poll(yourFounction, 5000, 100).then(function(result) {
// succeeded here
}).catch(function(err) {
// timed out here
})
Notice that both these schemes return a promise and then when the poll() function is done, they either call resolve or reject on that new promise and that will then trigger any .then() handlers to get called.
P.S. I should add that this all assumes your fn() is a synchronous function that returns a truthy or falsey value (which is what your code seems to presume). If your fn() is actually an asynchronous function with a callback or a promise, then that needs to be factored into the design. You would have to show us what the calling convention is for the function before we could write code to use that correctly.
Since you said you found polling functions that have callbacks, this basically boils down to "How do I promisify something?"
Use BluebirdJS's Promisify:
var poleYouFoundThatHasCallback = require('somePollLibrary');
var Promise = require('bluebird');
var poll = Promise.Promisify(poleYouFoundThatHasCallback);
poll.then((res) => {
//dostuff with res here
}).catch(err => console.log(err))
You can also throw a timeout on it for shits and giggles.
Here's and example from the docs:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
fs.readFileAsync("huge-file.txt").timeout(100).then(function(fileContents) {
}).catch(Promise.TimeoutError, function(e) {
console.log("could not read file within 100ms");
});

Categories

Resources