How does one await the result of a deferred operation with setTimeout? - javascript

function z(){
setTimeout(()=>{
console.log("A")
},3000)
}
z()
console.log("B")
output i expected
A(3 sec delay)
B
output i got
B
A(3 sec delay)
how to get synchronous behavior with this asynchronous code?

For a first solution the OP needs to ...
write a wait function which accepts a number value (representing milliseconds) and returns a Promise instance which resolves after the provided delay.
utilize the wait function by logging the to be delayed value after the awaited time via the promise' then method.
function wait(msec) {
return new Promise(resolve =>
setTimeout(resolve, msec)
);
}
console.log('A');
wait(3000)
.then(() => console.log('B'));
.as-console-wrapper { min-height: 100%!important; top: 0; }
For a second solution the above provided code could be rewritten into an async function which does log both of the OP's values and does, in between the logging, await the promise returned by wait.
function wait(msec) {
return new Promise(resolve =>
setTimeout(resolve, msec)
);
}
(async () => {
console.log('A');
await wait(3000);
console.log('B');
})();
.as-console-wrapper { min-height: 100%!important; top: 0; }

Related

How can I set async for setTimeout in JavaScript

const delayTime = (time) =>
setTimeout(() => {
console.log("run after:", time);
}, time);
const runTime = async () => {
await delayTime(1000);
await delayTime(900);
};
runTime();
And actual result is:
run after: 900
run after: 1000
And expected result I want:
run after: 1000
run after: 900
Async/await works with promises under the hood, so you need to return a promise from your delayTime function.
The Promise constructor accepts an executor function that is run synchronously (ie. immediately) with two callback functions as arguments: one to resolve the promise and another to reject the promise.
setTimeout and setInterval were added to JavaScript years before promises were widely understood, and are therefore not immediately compatible with promises: you need to "promisify" them.
To promisify a setTimeout expression you wrap it in a promise executor function and call the resolve callback function from inside the setTimeout callback .
const delayTime = (time) =>
new Promise((resolve) => setTimeout(() => {
console.log("run after:", time);
resolve();
}, time));
const runTime = async () => {
await delayTime(1000);
await delayTime(900);
};
runTime();
It's more logical to have timeout function separately, and call action (log) in caller function:
// Timeout function
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
// Caller function
const test = async () => {
// Do all stuff here
console.log(`starting...`);
await timeout(3000);
console.log(`3 sec passed...`);
await timeout(5000);
console.log(`8 sec passed, finishing.`);
}
// Run test
test();
The reason your you see 900 hundred printed earlier is that the time out set for setTimeout is not constant. 900 milliseconds pass faster than 1000 millisecs, so hence 900 is printed earlier.
I have changed the method to pass the time-out delay with the respective message. Here is the implementation:
const delayTime = ( delay, displayMessage) =>
setTimeout(() => {
console.log("run after:", displayMessage );
}, delay);
const runTime = async () => {
await delayTime(1000, '1000');
await delayTime(1000, '900');
};
runTime();

Why does this sequence of await function calls run in the wrong order?

I want to output some text after 2 seconds first, after output some "alert()" second and at the end output some "console.log" by using only async/await. Please help me how to write such a sequence?
Why the code below does not work
async function qaz()
{
let res1 = await setTimeout(function(){
console.log("show me first");
}, 2000);
let res2 = await alert('show me second');
let res3 = await console.log('show me at the end');
return [res1,res2,res3];
}
The setTimeout is part of the JavaScript asynchronous methods (methods that are starting to execute and their result will return sometime in the future to a component called the callback queue, later to be executed)
What you probably want to do is to wrap the setTimeout function within a Promise and await it and then execute the rest of the synchronous code.
const longTask = () => new Promise(resolve => {
setTimeout(function(){
console.log("show me first");
resolve();
}, 2000);
});
async function qaz()
{
await longTask();
alert('show me second');
console.log('show me at the end');
}
qaz();
I suggest to read more about the event loop model here
Neither the setTimeout, the alert, or the console.log return promises, and that's a problem because await only works with promises.
You can still use async/await, however. Create a delay function that returns a promise you can await for the first part, and then after that resolves do your alerts and your logging.
function delay(n) {
return new Promise(res => {
setTimeout(() => res(), n);
});
}
async function qaz() {
await delay(2000);
console.log('Show me first');
alert('Show me second');
console.log('Show me at the end');
}
qaz();

Console log not printing in awaited promise in an async function

function sleep(cb, ms) {
return new Promise((cb) => setTimeout(cb, ms));
}
async function delayedGreeting() {
console.log("Hello");
await sleep(myfun, 1000);
console.log("World!");
}
function myfun() {
console.log("whatever");
}
delayedGreeting();
console.log("Goodbye!");
Can someone please explain in the context of Eventloop, Callback Queue and Stack as to what is happening here as I don't see the word 'whatever' in the output. Is there a mistake in the code and if so what is it?
You forgot to add parenthesis for myfun function parameter on this line await sleep(myfun, 1000);.
DEMO
function sleep(cb, ms) {
return new Promise((cb) => setTimeout(cb, ms));
}
async function delayedGreeting() {
console.log("Hello");
await sleep(myfun(), 1000);
console.log("World!");
}
function myfun() {
console.log("whatever");
}
delayedGreeting();
console.log("Goodbye!");
There are some minor mistakes in the code. I am pointing them below.
You should write resolve in the Promise.
return new Promise((resolve) => resolve (setTimeout(()=>{cb()}, ms)));
If you want myfun to run after a timeout of 1000 millisecond, you must call the function in the settimeout first parameter. Like this,
setTimeout(()=>{cb()}, ms);
Here is the updated source code,
function sleep(cb, ms) {
return new Promise((resolve) => resolve (setTimeout(()=>{cb()}, ms)));
}
async function delayedGreeting() {
console.log("Hello");
await sleep(myfun, 1000);
console.log("World!");
}
function myfun() {
console.log("whatever");
}
delayedGreeting();
console.log("Goodbye!");
And the right output according to the implementation that you are trying the code should be like this,
Hello
Goodbye!
World!
whatever
You should try like this -
function sleep(cb, ms) {
return new Promise((resolve) => resolve(setTimeout(cb, ms)));
}
It seems you are overriding the cb value inside promise.

Is setTimeout required?

I have a question to async, await and setTimeout().
I thought, I use asynchron functions for slow processes. So I tried it with a large loop. On my Computer, it needs few seconds to run the following code:
function slowFunction() {
return new Promise(resolve => {
setTimeout(() => {
for (let i = 0; i < 4000000000; i++) {};
resolve('Ready at ' + new Date().toLocaleTimeString('de'));
}, 0);
});
};
console.log('Start: ' + new Date().toLocaleTimeString('de'));
(async () => {
console.log('Call slow function.');
console.log(await slowFunction());
})();
console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));
The output is:
Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:20
Ready at 16:39:23
And now the question: What is the difference to the next code:
function slowFunction() {
return new Promise(resolve => {
for (let i = 0; i < 4000000000; i++) {};
resolve('Ready at ' + new Date().toLocaleTimeString('de'));
});
};
console.log('Start: ' + new Date().toLocaleTimeString('de'));
(async () => {
console.log('Call slow function.');
console.log(await slowFunction());
})();
console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));
The output is:
Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:23
Ready at 16:39:23
By the first example, it looks like asynchron. By the second example, the function wait for the end of loop.
Do I have to use setTimeout or do I have an error in the code or am I getting it wrong? I both cases, the resolve statment is behind the large loop.
The most examples for async and await used setTimeout, but I think, it's just to simulate a break.
Thanks for your help in advance.
Best greets
Pascal
TL:DR
Promises and async functions don't offload your code to another thread. If you want to move that long-running process off the main thread, on browsers look at web workers, and on Node.js look at child processes.
Details
Promises and async functions (which are just a syntax for creating and consuming promises) don't move your processing to any other thread, it still happens on the same thread you start the process on. The only thing they do is ensure that then and catch callbacks are called asynchronously. They don't make your code asynchronous (other than that one thing, ensuring the callbacks happen asynchronously).
So your first block using setTimeout just sets a timeout, returns a promise, and then when the timeout expires it blocks the main thread while your slow-running process executes. This just changes when the blocking happens a little bit, it doesn't change the fact of the blocking.
You can see that effect here, notice how the counter pauses when the long-running process occurs:
function slowFunction() {
return new Promise(resolve => {
setTimeout(() => {
const stop = Date.now() + 2000;
while (Date.now() < stop) {
// busy wait (obviously, never really do this)
}
}, 1000);
});
};
console.log("before slowFunction");
slowFunction()
.then(() => {
console.log("then handler on slowFunction's promise");
})
.catch(console.error);
console.log("after slowFunction");
let counter = 0;
const timer = setInterval(() => {
console.log(++counter);
}, 100);
setTimeout(() => {
clearInterval(timer);
console.log("done");
}, 3000);
.as-console-wrapper {
max-height: 100% !important;
}
Your second block not using setTimeout just blocks right away, because the promise executor function (the function you pass new Promise) runs immediately and synchronously, and you're not doing anything to make it asynchronous.
You can see that here; the counter pauses right away, not later:
function slowFunction() {
return new Promise(resolve => {
const stop = Date.now() + 2000;
while (Date.now() < stop) {
// busy wait (obviously, never really do this)
}
});
};
console.log("before slowFunction");
slowFunction()
.then(() => {
console.log("then handler on slowFunction's promise");
})
.catch(console.error);
console.log("after slowFunction");
let counter = 0;
const timer = setInterval(() => {
console.log(++counter);
}, 100);
setTimeout(() => {
clearInterval(timer);
console.log("done");
}, 3000);
.as-console-wrapper {
max-height: 100% !important;
}
We don't even see the before slowFunction log appear until after the long-running code has finished, because the browser never got a chance to repaint, we had the thread hogged.
Regarding async functions: The code in an async function starts out synchronous, and is synchronous until the first await (or other construct, such as setTimeout, that schedules things to execute later). Only the code after that is asynchronous (because it had to wait).
Here's an example demonstrating that:
async function foo() {
console.log("before await");
await Promise.resolve();
console.log("after await");
}
console.log("before foo");
foo()
.then(() => {
console.log("then handler on foo's promise");
})
.catch(console.error);
console.log("after foo");
Here's the output of that:
before foo
before await
after foo
after await
then handler on foo's promise
Notice how before await occurs before after foo; it's synchronous with the call to foo. But then after await doesn't occur until later (because await Promise.resolve() has to make the code following it occur asynchronously; it's syntactic sugar for then, which promises not to call its handler synchronously even if the promise is already resolved).
The difference is that this is completely synchronous code:
return new Promise(resolve => {
for (let i = 0; i < 4000000000; i++) {};
resolve('Ready at ' + new Date().toLocaleTimeString('de'));
});
This statement will block the JavaScript thread and force it to wait until all of those 4 billion iterations have taken place. Then it will move on to the next statement. Since the console.log executes after this, it will not execute until that loop has finished.
That's why you are seeing a difference.

ES6 promises with timeout interval

I'm trying to convert some of my code to promises, but I can't figure out how to chain a new promise inside a promise.
My promise function should check the content of an array every second or so, and if there is any item inside it should resolve. Otherwise it should wait 1s and check again and so on.
function get(){
return new Promise((resolve) => {
if(c.length > 0){
resolve(c.shift());
}else{
setTimeout(get.bind(this), 1000);
}
});
}
let c = [];
setTimeout(function(){
c.push('test');
}, 2000);
This is how I expect my get() promise function to work, it should print "test" after 2 or 3 seconds max:
get().then((value) => {
console.log(value);
});
Obviously it doesn't work, nothing is ever printed
setTimeout has terrible chaining and error-handling characteristics on its own, so always wrap it:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
function get(c) {
if (c.length) {
return Promise.resolve(c.shift());
}
return wait(1000).then(() => get(c)); // try again
}
let c = [];
get(c).then(val => console.log(val));
wait(2000).then(() => c.push('test'));
While you didn't ask, for the benefit of others, this is a great case where async/await shines:
const wait = ms => new Promise(r => setTimeout(r, ms));
async function get(c) {
while (!c.length) {
await wait(1000);
}
return c.shift();
}
let c = [];
get(c).then(val => console.log(val));
wait(2000).then(() => c.push('test'));
Note how we didn't need Promise.resolve() this time, since async functions do this implicitly.
The problem is that your recursive call doesn't pass the resolve function along, so the else branch can never call resolve.
One way to fix this would be to create a closure inside the promise's callback so that the recursive call will have access to the same resolve variable as the initial call to get.
function get() {
return new Promise((resolve) => {
function loop() {
if (c.length > 0) {
resolve(c.shift());
} else {
setTimeout(loop, 1000);
}
}
loop();
});
}
let c = [];
setTimeout(function() {
c.push('test');
}, 2000);
get().then(val => console.log(val));
In the else case, you never resolve that promise. get might create another one, but it is returned to nowhere.
You should promisify your asynchronous function (setTimeout) on the lowest level, and then only chain your promises. By returning the result of the recursive call from a then callback, the resulting promise will resolve with the same result:
function delayAsync(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
function get(c) {
if (c.length > 0){
return Promise.resolve(c.shift());
} else {
return delay(1000).then(() => {
return get(c); // try again
});
}
}
What you need is a polling service, which checks periodically for specific condition prior proceeding with promise resolution. Currently when you run setTimeout(get.bind(this), 1000); you are creating a new instance of the promise without actually resolving the initial promise, because you don't reference to the initial resolve function that you created.
Solution:
Create a new callback function that you can reference to it inside the promise
Pass the resolve & reject as params in the setTimeout invocation e.g. setTimeout(HandlePromise, 1000, resolve, reject, param3, param4 ..); setTimeout API
function get() {
var handlerFunction = resolve => {
if (c.length > 0) {
resolve(c.shift());
} else {
setTimeout(handlerFunction, 1000, resolve);
}
};
return new Promise(handlerFunction);
}
let c = [];
setTimeout(function() {
c.push("test");
}, 2000);
get().then(value => {
console.log(value);
});
For more information look into javascript polling article
You could try this solution. Since JS needs to free itself to download the images, I use await within an asynchronous function and an asynchronous call to wake up JS after a delay
private async onBeforeDoingSomething() : void {
await this.delay(1000);
console.log("All images are loaded");
}
private delay (ms : number = 500) : Promise<number> {
return new Promise((resolve,reject) => {
const t = setTimeout( () => this.areImgsLoaded(resolve), ms);
});
}
private async areImgsLoaded (resolve) {
let reload = false;
const img = document.querySelectorAll('img');
console.log("total of images: ",img.length);
for (let i = 0; i < img.length; i++){
if (!img[i]["complete"]) {
console.log("img not load yet");
reload = true;
break;
}
}
if (reload) {
await this.delay();
}
resolve();
}
Use setInterval to check every second. Run this script to understand.
let c = [];
function get(){
return new Promise((resolve) => {
var i = setInterval(function(){
if(c.length > 0){
resolve(c.shift());
clearInterval(i);
}
}, 1000);
});
}
setTimeout(function(){
c.push('test');
}, 2000);
get().then((value) => {
console.log(value);
});

Categories

Resources