Calling a setTimeOut after another setTimeOut in Pure JavaScript - javascript

I have two setTimeOut here. The second setTimeOut must be called after the first time out.
setTimeout(() => {
mack.classList.add('loaded');
}, 3000);
setTimeout(() => {
location.reload(true);
}, 4000);
But I know that this is not a good solution on this. So I tried to do a Promise:
const timer = ms => new Promise(res => setTimeout(res, ms));
Promise.all([
timer(3000).then(mack.classList.add('loaded')),
timer(1000).then(location.reload(true))
])
This however, did not work. How can I fix this to make it call in order? Also, is there a version to do this using asynchronous?

You are nearly there,
To use timer the way you want, you can use async / await, just remember to be able to use await, it has to be called withing another async function, here I've just placed inside an IFFE to achieve this..
const timer = ms => new Promise(res => setTimeout(res, ms));
(async function () {
console.log('Waiting 3 seconds');
await timer(3000);
console.log('loaded');
await timer(1000);
console.log('reload');
}());

You are creating the promises, and then passing them to Promise.all, which waits for all of them simultaneously.
You want to start the second timer in response to the first timer.
This would do you you want:
timer(3000)
.then(() => {
mack.classList.add('loaded');
return timer(1000);
}).then(() => location.reload(true));
If you wanted this in an an async function:
async function example() {
await timer(3000);
mack.classList.add('loaded');
await timer(1000);
location.reload(true);
}
example().then(() => console.log('async function complete!'));

Related

Periodically resolving a promise in javascript

Let’s say I want to resolve some promise every 2 seconds AFTER the function is run.
I tried a pattern like this at first: setInterval(MyAsyncFunction, 2000), but of course this does not wait for the promise to resolve before calling the function again.
I also tried setInterval(async () => await MyAsyncFunction(), 2000), but this is basically the same thing since I’m just wrapping it in another promise that will resolve while the setInterval is ticking down.
Is there a way to do what I am trying to do with setInterval or is there some alternative way to do this using setTimeout?
A Promise resolves once only, so therefore cannot, by definition, resolve periodically.
If you define a delay function, which returns a promise that resolves after timeout ms...
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
you could use it in an async loop:
async function foo(){
for(let i = 0; i < 100; ++i){
console.log("azrael");
await delay(2000);
}
}
If what you want is to call async function, then await for it, then wait extra fixed time, then repeat, you may approach it following ways.
You can call setTimeout from that function itself, so it will schedule its next run when it's finished:
async function myAsyncFunction() {
return new Promise(resolve => setTimeout(() => {
resolve('result'); // resolves, then
setTimeout(async () => { // schedules
let result = await myAsyncFunction(); // self-call
console.log('result') // and handles the result
}, 2000); // after extra 2s
}, 2000)); // imitates async function with 2s delay
}
async function main() {
let firstResult = await myAsyncFunction();
console.log(firstResult); // handles first call
}
More clean way is to wrap it in another async function with same setTimeout inside:
async function myAsyncFunction() {
// imitates async function
return new Promise(resolve => setTimeout(() => resolve('result'), 2000));
}
async function delayLoop() {
let result = await myAsyncFunction(); // waits for it
console.log(result);
setTimeout(delayLoop, 2000); // calls itself after extra 2s
}
delayLoop();
This way you do not have to modify original async function code and put callback right in there.
Both examples will await for async function for 2s before first result, and for 4s between calls - 2s async function delay + 2s extra delay after it.

JavaScript Sequential function execution for multiple functions

I (first time JavaScript user since yesterday) managed to get JavaScript to run functions in sequential execution order (see code below) (credit to #CertainPerformance). I need to use the fastFunction in multiple slowFunctions. The current solution does not seem DRY (do not repeat yourself) to me and at the same time it does not guarantee the exectution order of slowFunction1 and then slowFunction2. What is the DRY solution to this problem in JavaScript? Can I force JavaScript to always run in sequential mode by some configuration? Using nested callbacks does not seem to be the most intelligent solution to me.
function fastFunction(message) {
console.log(message);
}
function slowFunction1(callback, message) {
setTimeout(() => {
console.log('slowFunction1!');
callback(message);
}, 10000);
}
function slowFunction2(callback, message) {
setTimeout(() => {
console.log('slowFunction2!');
callback(message);
}, 1000);
}
slowFunction1(fastFunction, 'fast_Function');
slowFunction2(fastFunction, 'fast_Function');
With async/await you can sequence asynchronous tasks as follows:
// Very handy utility function to get a promise that resolves after a given delay
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function fastFunction(message) {
console.log(message);
}
async function slowFunction1(callback, message) {
console.log('slowFunction1!');
await delay(2000); // two seconds
callback(message);
}
async function slowFunction2(callback, message) {
console.log('slowFunction2!');
await delay(1000); // one second
callback(message);
}
(async function() {
// Put all your logic here, and await promises...
await slowFunction1(fastFunction, 'fast_Function');
await slowFunction2(fastFunction, 'fast_Function');
})(); // execute immediately
Now you will have the delays happening one after the other completes, so 2+1=3 seconds in (approximate) total execution time.
This mimics most what you had as pattern, but once you are using promises, you don't need the callback pattern anymore and can do it like this:
// Very handy utility function to get a promise that resolves after a given delay
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function fastFunction(message) {
console.log(message);
}
(async function() {
console.log('slow part 1');
await delay(2000); // two seconds
fastFunction('fast_function');
console.log('slow part 2');
await delay(1000); // one second
fastFunction('fast_function');
})(); // execute immediately

async function as argument to setInterval nodejs

When I pass an async function as argument to setInterval, it has a strange behaviour: it works a few times but then stops without any exception.
setInterval(() => doSomethingAsync(), 1000);
I have no idea why.
I tried to implement my own setIntervalAsync but the behaviour is the same:
const sleep = ms => new Promise(res => setTimeout(res, ms));
const setIntervalAsync = async (func, interval) => {
while (true) {
await func();
await sleep(interval);
}
};
// schedule it
setIntervalAsync(async () => await doSomethingAsync(), 1000);
The problem was elsewhere and completly unrelated to setInterval or my callback.
setInterval is working fine with async functions.

How to delay part of a function?

I would like to execute half of the a function and wait 1 second or 2 and then execute the rest, I tried like this, but I don't understand how to put a function inside another.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
$('#music_action').click(function() {
if($(menu_start_animation).hasClass('menu_start_animation')) {
$(menu_start_animation).removeClass('menu_start_animation');
$(menu_start_animation).addClass('favorites_back_animation');
await sleep(2000);
$(menu_start_animation).removeClass('favorites_back_animation');
$(menu_start_animation).addClass('music_animation');
}
});
You just need to make your click callback async.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
$('#music_action').click(async function () {
if ($(menu_start_animation).hasClass('menu_start_animation')) {
$(menu_start_animation).removeClass('menu_start_animation');
$(menu_start_animation).addClass('favorites_back_animation');
await sleep(2000);
$(menu_start_animation).removeClass('favorites_back_animation');
$(menu_start_animation).addClass('music_animation');
}
});
If you want to accomplish this using await, you should to make the function asynchronous or it will throw a syntax error, await wont work using regular functions. Here is an example of how to accomplish what you're trying to do asynchronously.
sleep = async (ms) => {
await new Promise((resolve, reject) => setTimeout(resolve, ms));
}
onClick = async () => {
console.log('first task')
// wait 2 seconds
await sleep(2000);
console.log('second task')
}
onClick()
However, for this use case you might not need to accomplish this asynchronously. Using setTimeout() seems async, but it runs concurrently in the background and uses less memory - asynchronous functions break a synchronous flow, but they don't necessarily execute in a concurrent order. In your case, it might be best to use a callback function.
/**
* Basic example updating a string
* In your case, the callback function would be adding and removing whatever you
* needed to in the second half of your function
*/
let word = 'init'
function sleep (callback, ms) {
setTimeout( () => {
word = 'updatedWord'
callback()
}, ms)
}
sleep(function () {
alert(word)
}, 2000)

Why does my timeout wait until after the await completes but my log does not?

If I have something like this setup:
<-- language: lang-javascript -->
console.clear();
// noprotect
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve('future value'), 500);
});
async function asyncFunction() {
const result = await fetchSomething();
console.log('waiting');
setTimeout(()=>console.log('waiting?'), 250);
return result + ' 2';
}
asyncFunction().then(result => console.log(result));
And my output looks like:
"waiting"
"future value 2"
"waiting?"
I would expect the waiting? to execute before the result completes, but for some reason it waits on the function. What makes one wait but the other execute?
It is a feature of Asynchronous programming.
You have to add await and wrap your setTimeout(()=>console.log('waiting?'), 250); with a function which returns Promise in order to make it look like it was evaluated continuously.
Something like:
await ((ms) =>{
console.log('waiting?');
return new Promise(resolve => setTimeout(resolve, ms));
})(250);
Or:
await (() => new Promise(resolve => setTimeout(()=>{
console.log('waiting?');
resolve();
}, 250)))();
Mind you, JS has a single threaded run-time engine, so it interrupts evaluation when original script reaches it's end.
And function in setTimeout(function, timeout) is evaluated by JS when it has a first chance and time is right.
So your function was interrupted twice and was resumed twice.
The call to log "waiting?" is started by a setTimeout after the await has finished, so after the 500ms in fetchSomething have already passed. It will only execute 250ms after fetchSomething has returned. That is enough time for asyncFunction to return.
If you want to see a different behaviour, start the timer for logging "waiting?" before calling await:
async function asyncFunction() {
setTimeout(()=>console.log('waiting?'), 250);
const result = await fetchSomething();
console.log('waiting');
return result + ' 2';
}

Categories