Callback after all functions done - javascript

This is just such a task, challenge, literally, everything that I have outlined is all information
We can add another argument for callback 'all is done'.
Important, console.log('all is done') need to be displayed only after all
'timer' functions have completed their execution, regardless of their call order.
I can’t figure out which way to approach the task, I need to output using callback, but I need to wait for all calls to be completed
What we have:
//Write a “timer” function which takes a function and timeout, after all executions fire a callback (‘all is done’):
const timer = // your code
timer( () => {
console.log(500)
}, 500 )
timer( () => {
console.log(3000)
}, 3000 )
timer( () => {
console.log(1500)
}, 1500 )
timer( () => {
console.log(2500)
}, 2500 )

If it is a promise related question, your constance returns a function with promise:
const timer = (timeout) => {
return new Promise(function(resolve, reject) {
setTimeout(function(timeout) {
resolve(() => { console.log(timeout)});
}, timeout);
});
}
Promise.all().then( () => { alert("All is done") })

This is how I solved the problem.
It would be cool to solve it without using a global variable.
//Write a “timer” function which takes a function and timeout, after all executions fire a callback (‘all is done’):
let maxTimer = 0;
const timer = async (toRun, timeout) => {
++maxTimer
const done = await new Promise((resolve, reject) => {
setTimeout(() => {
toRun()
resolve()
}, timeout)
} )
if (maxTimer === 0){
console.log('all is done')
}
}// your code
timer( () => {
console.log(6000)
--maxTimer
}, 6000 )
timer( () => {
console.log(500)
--maxTimer
}, 500 )
timer( () => {
console.log(1500)
--maxTimer
}, 1500 )
timer( () => {
console.log(7000)
--maxTimer
}, 7000 )
timer( () => {
console.log(2500)
--maxTimer
}, 2500 )

Related

How to control setTimeout with promises

var functionsArray = [
function() {
setTimeout(function() {
console.log(1);
}, 100);
},
function() {
setTimeout(function() {
console.log(2);
}, 200);
},
function() {
setTimeout(function() {
console.log(3);
}, 10);
}
],
Say I have an array of functions like above(the number of functions in it is not known). I want to write a function which takes this array as parameter and executes them in sequence. In the example above, I want it to log 1,2,3 in the sequence. Since Promise.all does not guarantee the order of execution, is it possible to achieve this without callback hell?
You can't get a promise from a function that just calls setTimeout - it needs some help, e.g.:
function after(n, f) {
return () => new Promise(resolve => {
setTimeout(() => {
resolve(f());
}, n);
});
}
with usage:
var functionsArray = [
after(100, () => console.log(1)),
after(200, () => console.log(2)),
after( 10, () => console.log(3)),
];
With that array you can then just await each function in turn:
for (let f of functionsArray) {
await f();
}
You can write an simple setTimeoutPromise function:
function timeoutPromise(time = 0){
return new Promise(resolve => setTimeout(resolve, time)
}
await timeoutPromise(10);
console.log('waited 10 sec')
timeoutPromise(20).then(() => console.log('waited 20 sec')
//make a new array as you like
Promise.all([
timeoutPromise(100).then(() => console.log(1)),
timeoutPromise(200).then(() => console.log(2)),
timeoutPromise(300).then(() => console.log(3))
])

How to schedule multiple timeout functions

I have a scenario where I need to schedule multiple timeouts in vanilla JS, it will be something like this below:
const scheduler = {
done: function() {},
schedule: function() {}
};
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(1);
done()
}, 2000);
});
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(2);
done()
}, 1000);
});
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(3);
done()
}, 3000);
});
it should execute it in such a way that it must print below:
1
2
3
This is a nice use case of promises.
These objects allow the abstraction over asynchronous operations, and fortunately, can be chained.
const scheduler = {
last: Promise.resolve(),
schedule(cb){
this.last = this.last.then(() => new Promise(cb))
}
}
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(1);
done()
}, 2000);
});
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(2);
done()
}, 1000);
});
scheduler.schedule(function(done) {
setTimeout(() => {
console.log(3);
done()
}, 3000);
});
However, if you use this with promises you obtained from elsewhere , it can quickly turn into the Explicit Promise construction antipattern, so, for a more general code, move the new Promise() part out of the schedule method:
const scheduler = {
last: Promise.resolve(),
schedule(cb){
this.last = this.last.then(cb)
}
}
scheduler.schedule(function() {
return new Promise(done => {
setTimeout(() => {
console.log(1);
done()
}, 2000);
})
});
scheduler.schedule(function() {
return new Promise(done => {
setTimeout(() => {
console.log(2);
done()
}, 1000);
})
});
scheduler.schedule(function() {
return new Promise(done => {
setTimeout(() => {
console.log(3);
done()
}, 3000);
})
});
You would need a que for the timeouts, eg:
const scheduler = {
done:function(){}, // Not sure what this function is supposed to do
schedule:function(callback, timeout) {
scheduler.que.push([callback, timeout]); // Add the function along with its wait time
if(scheduler.que.length == 1) scheduler.startQue(); // If the que was previously empty, start the execution of the que
},
startQue() {
setTimeout(() => {
scheduler.que[0][0](); // run the callback timeout
scheduler.que.shift(); // Remove the just ran timeout
if(scheduler.que.length >= 1) scheduler.startQue(); // Start another timeout if we still have some in the que
}, scheduler.que[0][1]);
},
que: []
};
scheduler.schedule(() => console.log(1), 2000); // Wait for 2 seconds to print
scheduler.schedule(() => console.log(2), 1000); // Wait 1 second after the first one printed
scheduler.schedule(() => console.log(3), 3000); // Wait another 3 seconds after the second one
const scheduler = {
done: function (cb) {
cb();
this.timeouts.shift();
this.timeouts[0] && this.timeouts[0]();
},
schedule: function (cb, ms) {
const timeout = () => setTimeout(this.done.bind(this), ms, cb);
this.timeouts.push(timeout) == 1 && timeout();
},
timeouts: [],
};
scheduler.schedule(() => console.log('1'), 2000);
scheduler.schedule(() => console.log('2'), 1000);
scheduler.schedule(() => console.log('3'), 3000);

How to repeatedly call asynchronous function until specified timeout?

I want to keep calling asnchronous api requests repeatedly until it exceeds specified time. Using async-retry we can only specify retrycount and interval, we wanted to specify even timeout in the parameter.
Can you just suggest a way?
// try calling apiMethod 3 times, waiting 200 ms between each retry
async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {
// do something with the result
});
Here is what you want :
const scheduleTrigger = (futureDate) => {
const timeMS = new Date(futureDate) - new Date();
return new Promise((res, ref) => {
if (timeMS > 0) {
setTimeout(() => {
res();
}, timeMS);
} else {
rej();
}
})
}
//const futureDate = '2020-07-23T20:53:12';
// or
const futureDate = new Date();
futureDate.setSeconds(futureDate.getSeconds() + 5);
console.log('now');
scheduleTrigger(futureDate).then(_ => {
console.log('future date reached');
// start whatever you want
stopFlag = false;
}).catch(_ => {
// the date provided was in the past
});
const wait = (ms = 2000) => {
return new Promise(res => {
setTimeout(_ => {
res();
}, ms);
})
}
const asyncFn = _ => Promise.resolve('foo').then(x => console.log(x));
let stopFlag = true;
(async () => {
while (stopFlag) {
await asyncFn();
await wait();
}
})();
So you want to keep retrying for as long as its within a certain timeout? How about this:
// Allow retry until the timer runs out
let retry = true;
const timeout = setTimeout(() => {
// Set retry to false to disabled retrying
retry = false;
// Can also build in a cancel here
}, 10000); // 10 second timeout
const retryingCall = () => {
apiMethod()
.then(response => {
// Optionally clear the timeout
clearTimeout(timeout);
})
.catch(() => {
// If retry is still true, retry this function again
if (retry) {
retryingCall();
}
});
};
You can achieve what you want with this function:
const retryWithTimeout = ({ timeout, ...retryOptions}, apiMethod, callback) => {
let timedout = false;
const handle = setTimeout(
() => (timedout = true, callback(new Error('timeout'))),
timeout
);
return async.retry(
retryOptions,
innerCallback => timedout || apiMethod(innerCallback),
(err, result) => timedout || (clearTimeout(handle), callback(err, result))
)
};
It has the advantage of allowing you to use the functionality of async.retry, as you apparently want, and also allows the timeout to take place even when what exceeds the timeout is the apiMethod itself, not the waiting time.
Usage example:
retryWithTimeout(
{timeout: 305, times: 4, interval: 100},
(callback) => { callback('some api error'); },
(err, result) => console.log('result', err, result)
)

How to set a time limit to a method in NodeJs?

I have a use case, where I am doing an external API call from my code,
The response of the external API is required by my code further on
I am bumping into a scenario, where the external API call at times takes far too long to return a response,
casing my code to break, being a serverless function
So I want to set a time limit to the external API call,
Where if I don't get any response from it within 3 secs, I wish the code to gracefully stop the further process
Following is a pseudo-code of what I am trying to do, but couldn't figure out the logic -
let test = async () => {
let externalCallResponse = '';
await setTimeout(function(){
//this call sometimes takes for ever to respond, but I want to limit just 3secs to it
externalCallResponse = await externalCall();
}, 3000);
if(externalCallResponse != ''){
return true;
}
else{
return false;
}
}
test();
Reference -
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property
I'm using AWS SSM's getParameters method
You cannot await setTimeout as it doesn't returns a Promise.
You could implement a function that returns a Promise which is fulfilled after 3 seconds.
function timeout(seconds) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1000)
});
}
You can await the above function in your code passing the number of seconds you want to wait for
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await externalCall();
}, 0);
await timeout(3); // wait for 3 seconds
if(externalCallResponse != '') return true;
else return false;
}
Following code snippet demonstrates the usage of timeout function written above. It mocks a api request that returns a response after 4 seconds.
function timeout(seconds) {
return new Promise(resolve => {
setTimeout(resolve, seconds * 1000);
});
}
function apiRequest() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 4000);
});
}
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await apiRequest();
}, 0);
await timeout(3); // wait for 3 seconds
if (externalCallResponse != '') return true;
else return false;
};
test()
.then(res => console.log(res))
.catch(err => console.log(err.message));
you can use something like this, I created a function that return a promise then I used this promise.
let test = async () => {
return promiseTimeout()
}
const promiseTimeout = () => {
return new Promise(async (resolve, reject) => {
setTimeout(function () {
let externalCallResponse=""
externalCallResponse = await externalCall();
if (externalCallResponse != '') {
return resolve(true);
}
else {
return resolve(false);
}
}, 3000);
})
}
test().then(result=>{
console.log(result);
});
You could do something like this:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
timeout(() => doStuff(), 3000)
.then(() => console.log('worked'))
.catch(() => console.log('timed out'));
Tests:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
const doStuffShort = async () => { // Runs for 1 second
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
const doStuffLong = async () => { // Runs for 5 seconds
return new Promise((resolve) => setTimeout(() => resolve(), 5000));
}
timeout(() => doStuffShort(), 3000)
.then(() => console.log('1 worked'))
.catch(() => console.log('1 timed out'));
timeout(() => doStuffLong(), 3000)
.then(() => console.log('2 worked'))
.catch(() => console.log('2 timed out'));

Ajax promise is executed in same time instead of sequentially

I work with an application which sends some requests to server.
function createAjaxCall(data, done, fail) {
return $.post("process_watch.php", data).then(done).fail(fail);
}
and
function step1() {
return createAjax({ }, function(result) { console.log(result); return result; }, function() { });
}
function step2(res) {
return createAjax({ }, function(result) { console.log(result); return result; }, function() { });
}
...
Some requests take a while (let's assume that I use sleep(1500); in PHP) and if I do:
step1().then((data) => step2(data)).then((data) => step3(data)) then will execute in same time.
What is going wrong ?
There is nothing parallel going on in javascript. It's a concurrent language .What you wrote will be executed serially ( one after another ).It will take 1500*3 ms to finish (assuming each take 500 ms)
step1().then((data) => step2(data)).then((data) => step3(data))
To make them execute concurrently ( a.k.a parallel in js) you should do the following. All the call will be sent out to fetch data.When all of them resolves promise will go to the then-catch chain.It will take more or less 1500 ms to finish ( assuming each takes 500 ms)
Promise.all([step1(),step2(),step3()]).then().catch()
You can use async function
An async function returns a Promise, so you can wait for the sync executions end, and then work with the returned result.
Look this code snippet
function step1() {
return new Promise((resolve) => {
setTimeout(function() {
resolve(1);
}, 1000);
});
}
function step2() {
return new Promise((resolve) => {
setTimeout(function() {
resolve(2);
}, 1000);
});
}
function step3() {
return new Promise((resolve) => {
setTimeout(function() {
resolve(3);
}, 1000);
});
}
async function process() {
var one = await step1();
var two = await step2();
var three = await step3();
/*if (some error) {
return Promise.reject('Some error!');
}*/
return `RESULT: ${one} - ${two} - ${three}`
}
console.log('Waiting results...');
process().then((result) => {
console.log(result);
console.log('DONE!');
}).catch((error) => {
console.log(error);
});
Resource
async function
Promise.reject()

Categories

Resources