I have wrote the following code:
async function imaAsyncFunction () {
console.log('1234');
let res = await setTimeout(()=>{console.log('10 sec');},10000);
console.log(res);
console.log('is After?!?');
}
imaAsyncFunction();
console.log('bla bla bla');
I was a little surprise that '1234' isn't printed at all. In addition the line console.log(res); was printed before the 10 seconds of timeout was finished, but i guess that the reason is that the code after await doesn't return a Promise.
But, why does the code : console.log('bla bla bla'); was printed before both lines:
console.log(res);
console.log('is After?!?');
If we saw that the code doesn't postpone because of the setTimeout() so why both line of codes don't run before the function is finished and only after that the console.log('bla bla bla'); should run?
What am I missing here?
Does all async function code will run i a different thread?
No. async functions, await, and promises do not create or use different threads.
A promise doesn't make anything asynchronous on its own¹, it's just a way of observing the completion of something that's already asynchronous (like your timer callback, which uses the timer subsystem of your environment to call your timer callback later).
async functions are "just" a way (a really, really useful way) to wait for promises to settle via syntax rather than by attaching fulfillment and rejection handlers using the .then or .catch methods.
I was a little surprise that the line console.log(res); was printed before the 10 seconds of timeout was finished, but i guess that the reason is that the code after await doesn't return a Promise.
setTimeout doesn't return a promise, right. So await doesn't wait for the timer callback to occur. See this question's answers for how you'd make a promise-enabled version of setTimeout.
But, why does the code : console.log('bla bla bla'); was printed before both lines:
For the same reason: Your async function returns a promise, and your code calling your async function doesn't wait for that promise to be settled before moving on to the console.log('bla bla bla') line.
Here's code that both uses a promise-enabled version of setTimeout and waits for your async function's promise to settle before doing the console.log:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function imaAsyncFunction () {
let res = await delay(800); // 0.8s instead of 10s
console.log("Timer expired");
console.log(res); // undefined, since we haven't set a fulfillment value
console.log("is after");
}
imaAsyncFunction()
.then(() => {
console.log("bla bla bla");
})
.catch(error => {
console.error(error);
});
If you wanted the delay function to return a fulfillment value, we could do this:
function delay(ms, value) {
return new Promise(resolve => setTimeout(() => {
resolve(value);
}, ms));
}
although in all standard environments (now), setTimeout accepts a value to pass to its callback, so we can do just:
function delay(ms, value) {
return new Promise(resolve => setTimeout(resolve, ms, value));
}
function delay(ms, value) {
return new Promise(resolve => setTimeout(resolve, ms, value));
}
async function imaAsyncFunction () {
let res = await delay(800, 42); // 0.8s instead of 10s
console.log("Timer expired");
console.log(res); // 42
console.log("is after");
}
imaAsyncFunction()
.then(() => {
console.log("bla bla bla");
})
.catch(error => {
console.error(error);
});
In a comment you've said:
i still can't understand why both lines doesn't runs before the `console.log('bla bla bla');?
Here's your original code:
async function imaAsyncFunction () {
console.log('1234');
let res = await setTimeout(()=>{console.log('10 sec');},10000);
console.log(res);
console.log('is After?!?');
}
imaAsyncFunction();
console.log('bla bla bla');
When you run that code, here's what happens, in order:
The function imaAsyncFunction is created.
The call to imaAsyncFunction() is executed:
The synchronous part of the function is run:
console.log('1234'); is executed
setTimeout(()=>{console.log('10 sec');},10000) is executed
setTimeout returns undefined
The await is reached: (Note: I'm skipping some details below for clarity.)
Normally, when you do await p, p is a promise (or at least something like a promise). Since you've used it on undefined instead, await wraps undefined in a promise as though it called Promise.resolve(undefined) and used that as p instead of undefined.
All of the code that follows await in the function is attached to p as a handler for when p is fulfilled (since you haven't used try/catch — which is fine — so there's no rejection handler). When you attach a fulfillment or rejection handler to a promise, you create a new promise that gets settled based on what happens to the original promise and, if relevant, what happens when the fulfillment or rejection handler is called. Let's call that new promise p2.
Usually, p wouldn't be settled yet, but in this case it is, so the fulfillment handler (the rest of the code in imaAsyncFunction, after the await) is scheduled to run once the current synchronous work is completed. If p weren't settled, this wouldn't happen yet (it would happen later, when p is settled.)
Since there aren't any other await expressions in the function, the promise imaAsyncFunction implicitly created (let's call it p3) is resolved to p2. That means that when p2 settles, the promise from imaAsyncFunction is settled in the same way (it's fulfilled with the same fulfillment value as p2, or rejected with the rejection reason from p2).
imaAsyncFunction returns p3.
The call to imaAsyncFunction is done, so the next statement is executed: console.log('bla bla bla');
Code execution reaches the end of the script, which means all of the synchronous code has finished running.
The fulfillment handler code scheduled in Step 2.2 above is run:
It executes the console.log(res) and console.log('is After?!?').
It fufills p2 with undefined (since there's no return x in the function).
This schedules the fulfillment of p3, since p3 was resolved to p2. Doing that would scheduled execution of p3's fulfillment handlers, but it doesn't have any — nothing used await or .then or .catch, etc., on imaAsyncFunction()'s return value.
¹ There's one caveat to that statement: When you attach a fulfillment or rejection handler to a promise, the call to that handler is always asynchronous even if the promise is already settled. That's because it would be asynchronous if the promise weren't settled, and it would be chaotic if the call to your handler was synchronous in some situations but asynchronous in others, so it's always done asynchronously. But that's literally the only thing about promises or async functions that makes anything asynchronous, the rest just observes things that are already asynchronous.
Related
This question already has answers here:
What is the intention behind clause 2.2.4 of Promise/A+ spec?
(1 answer)
Why are javascript promises asynchronous when calling only synchronous functions?
(2 answers)
Why are Q.js promises asynchronous after they have been resolved?
(2 answers)
Closed last year.
As I understand a promise is something that can resolve() or reject(), and this action should be done after some work as completed, so it should be invoked as part of the callback like in this example:
let timeout = new Promise((resolve) => {
console.log('function called');
setTimeout(() => {
console.log("timeout finisced!");
resolve()
}, 1000)
});
timeout.then(() => {
console.log("timeout resolved!")
});
console.log('teminated!');
result
function called
teminated!
timeout finisced!
timeout resolved!
But the thing I can't understand is how they work when there isn't an asynchronous action to do and so, if you think synchronously, the resolve function should be called in the constructor of the promise, even if you don't have a handler for it and then the then() method should be able to handle it after; but from what I can see from this example, the code is executed in the same way.
So can someone explain the thought behind why the following example works in this way?
new Promise(function(resolve) {
console.log('function called')
resolve();
}).then(() => {
console.log('function resolved');
});
console.log('teminated!');
result:
function called
teminated!
function resolved
Edit:
I have mostly understanded what’s happening, the thing that now I am not sure is how this is done.
So correct me if I’m wrong, the .then() method is always put in the micro task queue no matter what, so even if you pass it synchronous code, it is not executed in the stack directly like other synchronous code.
And for that to happen the state of the promise should be fulfilled or rejected, and to do that the function resolve() or reject() should be called.
So now I would like to understand the process that is behind it, like what does the then() method effectively do?
You pass it a callback and that is stored in the promise object or what?
And because the callback is put on the micro task queue after it is fulfilled or rejected, does that mean it is the resolve() function that puts it in the micro task queue?
That should be a reasonable assumption based on this example below; or does the resolve function only change the state and then is the then() method that puts it in the queue?
const p = Promise.resolve();
p.then(() => console.log("callback 1"));
const p2 = Promise.resolve();
p2.then(() => console.log("other micro task"));
p.then(() => console.log("callback 2"));
/*
result:
callback 1
other micro task
callback 2
*/
const p = Promise.resolve();
p.then(() => console.log("callback 1"));
const p2 = new Promise((resolve) => {
setTimeout(() => resolve(), 0)
});
p2.then(() => console.log("other micro task"));
p.then(() => console.log("callback 2"));
/*
result:
callback 1
callback 2
other micro task
*/
The only thing I’m sure of is that there are multiple callbacks for a single promise, they aren’t always executed one by one in order, but there can be another micro task before it like in the first example.
I'm aware that this may be a stupid problem, but for some reason it put's me in confusion, so thank's in advance for the help.
First, promises are async (then part), async/await is built on top of them. And the promise is not a simple async code, but a micro task, its executed after sync code, but before macro tasks (such as timeouts).
So in your case we have sync promise part function called, than sync code teminated, than async part after promise resolved function resolved.
To better undestand how micro/micro tasks and event loop works, I recommend you to check out answers here: Difference between microtask and macrotask within an event loop context
I'm learning Javascript async programming and Promise. I have the following code.
let promiseTest = () => new Promise((resolve, reject) => {
console.log("Inside Promise");
resolve('Promise is resolved');
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");
I have the function "promiseTest". I want to execute that asynchronously. In real world scenario, it could be a function that fetch the web service or query the database. I was expecting to have the following result from the code.
Before Promise
After Promise
Inside Promise
Promise is resolved
I was expecting that "console.log(" Inside Promise") " will be executed asynchronously since it is inside the Promise function. But the actual result is
Before Promise
Inside Promise
After Promise
Promise is resolved
As you see tin the actual result, Inside Promise is executed synchronously and blocking the main thread. Only the code inside "resolve" is asynchronous. Maybe, my current understanding of javascript Promise is incorrect. How do I modify my existing code to make sure the whole function " promiseTest " is executed asynchronously without blocking the main thread.
The executor function is executed synchronously. Promise doesn't make any code asynchronous; its just a mechanism to get notified when something, that is already asynchronous, has completed.
If you want to make a API call, that is already asynchronous and if you use the fetch API, then you don't need the promise constructor because fetch(...) already returns a promise.
Only the code inside "resolve" is asynchronous
In your code, resolve() function is also called synchronously; only the callback function of promiseTest().then(..) is invoked asynchronously.
How do I modify my existing code to make sure the whole function
"promiseTest" is executed asynchronously without blocking the main
thread.
You will have to use another thread. Even if you delay the execution of the promiseTest function using setTimeout, once it is pushed in the call stack, it will execute synchronously. Nothing else will execute when the delayed promiseTest function is being executed.
If delaying the execution is what you want, just wrap the promiseTest function call in setTimeout.
I'd suggest using setTimeout for your promiseTest function, this will give you the expected result.
setTimeout sets a timer which executes a function once the timer expires.
As you can see "After Promise" will be logged before "Promise is resolved", this is entirely expected, since the promise will take some time (in this case 1000 milliseconds) to resolve.
let promiseTest = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Inside Promise");
resolve('Promise is resolved');
}, 1000)
});
console.log("Before Promise");
promiseTest().then((data) => { console.log(data); });
console.log("After Promise");
async function f() {
let result = await new Promise((resolve) => setTimeout(resolve("done after 1sec"), 1000)); //(*)
console.log(result);
return Promise.resolve("done immediately"); //(**)
}
f().then((result) => console.log(result));
console.log("synchronous code");
My understanding as per the moment on this code is that:
1:The sting synchronous code will be logged first
2:followed by the execution of .then handler logging
done after asynchronous code, since function f returned an already resolved promise
3:And after 1sec the awaited promise inside function
f will be resolved and done will be logged.
But what am getting is:
1:synchronous code.
2: done after 1sec.
3: done after asynchronous code.
is as if the promise returned on line * is hindering the promise on line ** from resolving before it.
what am i over looking? Thanks in advance for any support
I have the following code:
const doWorkPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('#2 (async call)');
}, 0);
resolve('#3 (async call?)');
console.log('#1 (sync call)');
});
doWorkPromise.then((result) => {
console.log('Success!', result);
}).catch((error) => {
console.log('Error!', error);
});
The output is:
#1 (sync call)
Success! #3 (async call?)
#2 (async call)
I know that sync code lands on the call stack and the async code registers event-callback pair at the Node APIs, where the callback is moved to the callback queue after the event. The event loop is then going to take elements out of the callback queue only when the call stack is empty. Therefore, I expected to have the sync code executed first and then the async one in order, because the timeouts are 0s, like:
#1 (sync call)
#2 (async call)
Success! #3 (async call?)
Can someone please explain why resolve is executed before '#2 (async call)'?
reject is never executed.
resolved is executed before #2 because:
setTimeout puts a function on the time out queue
resolve resolves the promise
console.log logs #1
The function finished
doWorkPromise.then assigns a function to run when the promise resolves
The promise is already resolved so that function is executed
After the minimum timeout time passes the function passed to setTimeout is called and logs #2
Your code executes the following synchronously:
resolve('#3 (async call?)');
...so that promise gets immediately in a resolved state. The fact that you have started a timer, as no bearing on the promise... it is unrelated.
So the then callback on that promise will be triggered on the next processing of the job queue, and so you'll see "Success", right after the execution of the main, synchronous code has completed.
Somewhat later (yes, even setTimeout(..., 0) will introduce a small delay), the timer will expire, but that event has nothing to do with any promise.
The common pattern
When you create a promise with new Promise and want it to resolve some time later, then you could indeed use setTimeout, but then the idea is to call resolve only when that timer has expired. Otherwise the timer does not do anything that serves the promise:
setTimeout(() => {
resolve();
}, 0);
The difference between Code#1 and Code#2 is: Code#1 uses resolve(p) and Code#2 uses p.then(()=>resolve()). I would expect the sequence of output to be invariant, but they generate a different sequence. I cannot figure out why.
Code #1: resolve(p)
const p = Promise.resolve();
new Promise((resolve) => {
resolve(p); // <---
}).then(() => {
console.log('after:await');
});
p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));
Output:
tick:a
tick:b
after:await
tick:c
Code #2: p.then(()=>resolve())
const p = Promise.resolve();
new Promise((resolve) => {
p.then(()=>resolve()); // <---
}).then(() => {
console.log('after:await');
});
p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));
Output:
tick:a
after:await
tick:b
tick:c
Why is the order of output different?
This is in fact a very interesting question, because the Promise/A+ specs would allow the first code version to produce the same output as the second version of the code.
One could dismiss the question saying the Promise implementation says nothing about how resolve(p) would be implemented. This is a true statement when looking at the Promise/A+ specification, quoting from its preface:
the core Promises/A+ specification does not deal with how to create, fulfill, or reject promises, ...
But the EcmaScript specification for Promises (Section 25.4) is quite more detailed than the Promise/A+ specification and requires that "jobs" are added to the back of the relevant job queue -- which for promise settlements is the PromiseJobs queue (25.4.1.3.2 and 8.4): this determines a specific order:
Required Job Queues
[...]
PromiseJobs: Jobs that are responses to the settlement of a Promise
[...]
The PendingJob records from a single Job Queue are always initiated in FIFO order
It also defines that resolve(p) -- when p is a thenable -- will first put a job on the queue that will perform the necessary internal call of the p.then method. This is not done immediately. To quote the note in the EcmaScript specs at 25.4.2.2:
This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
This statement is illustrated with the order of output in the following snippet:
const p1 = Promise.resolve();
// Wrap the `p1.then` method, so we can log something to the console:
const origThen = p1.then;
p1.then = function(...args) {
console.log("The p1.then method is called asynchronously when triggered by resolve(p1)");
origThen.call(this, ...args);
};
const p2 = new Promise(resolve => {
resolve(p1);
console.log("Code that follows is executed synchronously, before p1.then is");
});
When we use the p1.then(resolve) method call instead of resolve(p1), we get the opposite order:
const p1 = Promise.resolve();
// Wrap the `p1.then` method, so we can log something to the console:
const origThen = p1.then;
p1.then = function(...args) {
console.log("The p1.then method is called synchronously now");
origThen.call(this, ...args);
};
const p2 = new Promise(resolve => {
p1.then(resolve);
console.log("Code that follows is executed synchronously, after p1.then is");
});
Your code
The above really explains the different order of output you get. Here is how the first code version sequences the actions. First let me rewrite this a bit, so that most involved promises have a name:
const p1 = Promise.resolve();
const p2 = new Promise((resolve) => resolve(p1));
const p3 = p2.then(() => console.log('after:await'));
const p4 = p1.then(() => console.log('tick:a'));
const p5 = p4.then(() => console.log('tick:b'))
const p6 = p5.then(() => console.log('tick:c'));
Now, after the main, synchronous code has executed to completion, only p1 has a resolved state, and two jobs are present on the job queue (micro tasks queue), one as a result of resolve(p1) and a second one because of p1.then:
According to 25.4.2.2,
the then method of p1 is called passing it the internal [[resolve]] function related to p2. The p1.then internals know that p1 is resolved and put yet another job on the queue to actually resolve p2!
The callback with "tick:a" is executed, and promise p4 is marked as fulfilled, adding a new job in the job queue.
There are now 2 new jobs in the queue, which are processed in sequence:
The job from step 1 is executed: p2 is now resolved. This means a new job is queued to actually call the corresponding then callback(s)
The job from step 2 is executed: the callback with "tick:b" is executed
Only later the job added in step 3 will be executed, which will call the callback with "after:await".
So, in conclusion. In EcmaScript a resolve(p), where p is a thenable involves an asynchronous job, which itself triggers yet another asynchronous job to notify the fulfilment.
The then callback, that differentiates the second code version, will only need one asynchronous job to get called, and thus it happens before the output of "tick:b".
In both your answers promise chain1 and promise chain2 can be interleaved differently. But, tick:a, tick:b, tick:c will be outputted in that order, tick:a before tick:b, and tick:b before tick:c. after:await can be outputted anywhere in between.
For what your code is doing.
// Returns a resolved promise object
// Which is equivalent to const p = new Promise(resolve => resolve());
const p = Promise.resolve();
// For Reference Call This Promise Chain 1
new Promise((resolve) => {
// Fulfills the promise with the promise object p
resolve(p); // (1)
}).then(() => {
console.log('after:await');
});
For Reference Promise Chain 2
p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));
const p = Promise.resolve();
new Promise((resolve) => {
// Here you are calling then which if promise p has been fulfilled
// will call the callback you passed as an argument, which then
// will eventually cause the outer promise to enter a state of
// fulfilled triggering a call to the next 'then' provided in the part of the chain.
p.then(()=>resolve());
}).then(() => {
console.log('after:await');
});
p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));
The Promise.resolve() method returns a Promise object that is resolved with a given value. If the value is a promise, that promise is returned; if the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value. This function flattens nested layers of promise-like objects (e.g. a promise that resolves to a promise that resolves to something) into a single layer.
Please refer here for more info about Promise.resolve().
The difference in the output of both of your codes is due to the fact that the then handlers are called asynchronously.
When using a resolved promise, the 'then' block will be triggered
instantly, but its handlers will be triggered asynchronously.
Please refer here for more info about then handlers' behaviour.
A Promise is in one of these states:
-pending: initial state, neither fulfilled nor rejected.
-fulfilled: meaning that the operation completed successfully.
-rejected: meaning that the operation failed.
A pending promise can either be fulfilled with a value, or rejected with a reason (error). When either of these options happens, the associated handlers queued up by a promise's then method are called.
Refer this for more details
Now in your particular case, you are using "Promise.resolve()" probably to create a new promise object but what it does is that it creates an already resolved promise with no value. So your promise object "p" is resolved during its creation and the rest of the code where you resolve it has literally no effect other than putting the "after:wait" into a handler queue. Please refer to the Event Loop with Zero Delay. The output for both the codes is different based on when the "console.log" is put in the call stack and not because how you are writing it.
The correct way of doing this can be:
var promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise1.then(function(value) {
console.log(value);// expected output: "foo"
});
console.log(promise1);// expected output: [object Promise]