Testing promises, I think, I've found a small mistake in this piece of documentation:
Unlike "old-style", passed-in callbacks, a promise comes with some guarantees:
Callbacks will never be called before the completion of the current run of the JavaScript event loop.
I've made a little script to test this behavior:
var m
console.log("test: init")
m = (new Promise(function(resolve, reject) {
console.log("test: inside 'Promise' callback")
resolve("O")
})).then(function(result) {
console.log("test: inside 'then' callback")
return result + "K"
})
setTimeout(function() {
console.log(">> another event-loop cycle: m =", m)
}, 0);
console.log("test: m =", m)
This is the console log in firefox:
```
test: init
test: inside 'Promise' callback
test: m = Promise {
undefined
test: inside 'then' callback
another event-loop cycle: m = Promise {
: "fulfilled", : "OK" }
鈥媊``
From this log seem that Promise-callback have been called in current event loop cycle.
I'd like to take on this one 馃
First hunch is it's because there's a different queue for setTimeout and promises, but I will confirm after rewatching Jake's In the loop talk
Sure thing. I've assigned you!
Hey @fabio-sassi
The reason why in your code you see the console log from the .then() callback is because it's a microtask
Whereas the setTimeout is queuing it into the task queues
But the microtask will run almost asap whenever possible, I'd definitely recommend watching this talk (you can start from the timecode I specified in the link) to better understand the concept: https://youtu.be/cCOL7MC4Pl0?t=1444
@chrisdavidmills do you think we should close the issue or would you like to have some update for the docs?
@jadjoubran thanks for looking into this Jad. I think it'd be nice to offer a bit more explanation of this, as there is a lot of misunderstanding here.
Sure thing, I just added a section on Task queues vs microtasks with a refactored example from @fabio-sassi (Thank you!) and linked to the MDN Tasks vs microtasks page.
It would be wise to get a quick technical review on what I authored in case I made a mistake.
@jadjoubran looks good, thanks! @fabio-sassi , what do you think?
Thank you so much @jadjoubran to have a look over this problem.
The video about microtask give a deeper and better comprehension
about the concept behind Promises.
I think my example code was a bit confused (I could avoid the
setTimeout).
I write it again in a more clear way:
console.log("sync - start")
var m = (new Promise(function(resolve, reject) {
console.log("Promise callback")
resolve()
})).then(function() {
console.log("Then callback")
})
console.log("sync - end")
This is the log:
sync - start
Promise callback
sync - end
undefined
Then callback
In the documentation, subject of this issue, we can read:
Callbacks will never be called before the completion of the current run of the JavaScript event loop.
but the promise-callback is called in a sync way, so code execution don't follow this rule!
This is similar to the Jake Archibald example at time 26:54 but in this
case 'Hey!' is printed before 'Yo!'
Also if promise-callback is a microtask, it should not be executed after console.log("sync - end")?
The then-callback instead called at the end of main execution as we expected.
Hey @fabio-sassi, sure thing happy that it's clearer now!
I think it's because the constructor of the promise is not a callback, which is why it's being called immediately. So I'd rewrite your code as following:
console.log("sync - start")
let m = (new Promise(function(resolve, reject) {
console.log("Creating promise")
resolve()
})).then(function() {
console.log("Then callback")
})
console.log("sync - end")
The promise constructor (the function that you pass to new Promise()) needs to run immediately so that it returns an instance of promise so that the .then() could would queue the callback in the future.
Does that make sense?
@jadjoubran, you are right!
I looked it up online and I found that argument of Promise is a called "during the process of constructing the promiseObj" here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
new Promise(executor)executor
A function to be executed by the constructor, during the process of constructing the promiseObj. The executor is custom code that ties an outcome to a promise.
My confusion now is about the semantic, because if executor can be considered a callback as defined in wikipedia:
https://en.wikipedia.org/wiki/Callback_%28computer_programming%29
then this sentence is wrong:
Callbacks will never be called before the completion of the current run of the JavaScript event loop.
because executor callback is called in the current event loop but if callback is defined as call-after:
https://stackoverflow.com/questions/824234/what-is-a-callback-function/7549753#7549753
the the sentence is correct.
Hey @fabio-sassi
The executor is not a callback.. I think you might be confusing that because the wikipedia page mentions executable code? that is different than executor
So far from the tests above, the sentence Callbacks will never be called before the completion of the current run of the JavaScript event loop. seems to be correct
Does that make sense?
Hey @jadjoubran
From wikipedia:
In computer programming, a callback, also known as a "call-after"[1] function, is any executable code that is passed as an argument to other code; that other code is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.
Executor is a function passed as argument of other code (the promise constructor) and "This execution may be immediate as in a synchronous callback" as in this case ... then why isn't a callback?
From the point of view of code workflow, executor is the same of PrintTwoNumbers's argument, in wikipedia page C example:
/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
int val1 = numberSource();
int val2 = numberSource();
printf("%d and %d\n", val1, val2);
}
[...]
int main(void) {
[...]
PrintTwoNumbers(&rand);
[...]
}
I know that callback used to be thought always as "asynchronous" but definition (at least in wikipedia) talk also of syncronous-callback.
From my point of view to avoid this semantic trap, the sentence: Callbacks will never be called before the completion of the current run of the JavaScript event loop. should be enriched with a note that exclude Promise argument from the "Callbacks" group.
Something like:
Callbacks will never be called before the completion of the current run of the JavaScript event loop (note: Promise argument is called in a sync way and must be excluded from ...
Hey @fabio-sassi
This is outside my experience but as far as I know, the function you pass as a constructor is not a callback. You can think of it as the constructor definition, so I don't see it as an exception