Sprints: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Created on 22 Aug 2019  路  13Comments  路  Source: mdn/sprints

Request type

  • [ ] Please close this issue, I accidentally submitted it without adding any details
  • [ ] New documentation
  • [x] Correction or update

Details

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 { : "pending" }
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.

JS Medium P2

All 13 comments

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.

https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Task_queues_vs_microtask

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

acolle picture acolle  路  4Comments

wbamberg picture wbamberg  路  6Comments

chrisdavidmills picture chrisdavidmills  路  6Comments

arturjanc picture arturjanc  路  5Comments

mattiapontonio picture mattiapontonio  路  5Comments