5

I'm so much confused about what happens behind the scenes when promise is produced and consume. Please clarify my points and sorry for my weak English.

  1. blank object is created with new keyword Promise constructor is called and new keyword set the this of Promise constructor points to the blank object this = blankobject.
  2. Promise constructor receives callback (executor function) in argument and calls the executor function.
  3. executor function receives two callbacks (resolve,reject) as arguments
  4. setTimeout gets called in the executor function and setTimeOut is async code
  5. async code goes to background and then Promise constructor returns Promise object formerly blank object and Promise object reference saved to myPromise.
  6. a variable is created

What happens next ? When then method is called the code of then method goes to background? I imagine it goes to background and a variable is console.log // 10

After main code execution finishes, async code start setTimeout callback begins to execute and after execution finishes promise is fulfilled and resolved function returns value. How is this value stored in promise object and what happens in then method ?

let myPromise = new Promise (
    (resolve, reject) => {

        setTimeout(() => {
            console.log(getIDs)
            resolve(10);

        }, 1500);

    }
)


let a = 10
        myPromise.then(val => {
            console.log(val);

        })
        console.log(a)
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 4
    You can find the answers to all these questions in the [DOCUMENTATION](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) – Titus Apr 26 '20 at 14:43
  • I want to see what then method does for us which i can't see, i'm thankful to you if you explain me with code example – javascript lover Apr 26 '20 at 14:55
  • For short, when you call `resolve(..)`, the callback function that you pass to `.then(..)` is executed. `myPromise` is just an instance of `Promise`. It will never be blank. As for *goes to background*, how that works depends on the JavaScript engine – Titus Apr 26 '20 at 15:04
  • in normal execution then method is called but callback which i pass in then method cannot called and code goes to next line and print a variable which i show in above example and then async code execution started after promise resolved callback in then method is called tell me if i'm correct and also tell me why i get -1 on my question i'm new in stackoverflow. – javascript lover Apr 26 '20 at 15:15
  • Related: [one](https://stackoverflow.com/questions/23772801/basic-javascript-promise-implementation-attempt?rq=1), [two](https://stackoverflow.com/questions/56613356/how-are-javascript-promises-handled-in-the-runtime-environment?noredirect=1&lq=1), [three](https://stackoverflow.com/questions/59450327/how-does-promise-in-javascript-work-under-the-hood-my-promise-implementation-do), [four](https://stackoverflow.com/questions/28896280/why-does-javascript-es6-promises-continue-execution-after-a-resolve?rq=1). – Ben Aston Apr 28 '20 at 22:08

2 Answers2

7

The following is a simplified implementation of the built-in Promise class. catch and finally have not been implemented.

The function supplied to the Promise constructor is called the executor function, and is invoked immediately and synchronously.

Every promise has a method .then, enabling the chaining of promises.

Functions supplied to .then are always invoked asynchronously on a microtask (note use of queueMicrotask below).

Every time .then is called, a new promise is created and returned.

.then can be called more than once on the same promise, creating a multicast of the result of the promise, and a branching of the promise chain.

A promise can be in one of three states: pending, fulfilled, or rejected. State transitions are unidirectional: you cannot move from fulfilled or rejected, back to pending.

If a promise is resolved with another promise, then the two promise chains are joined and the outer promise takes on the status of the inner promise (which could be pending), until the inner promise resolves.

function Promise(executor) {
  if (!executor) throw "Promise executor undefined"
  let status = "pending", value, thenQ = []

  const then = onFulfilled => {
    let resolver
    // This ensures control does not move to later promises 
    // until prior promises have been resolved.
    const nextPromise = new Promise(resolve => (resolver = resolve))
    // More than one "then" can be registered with each promise.
    thenQ.push((...args) => resolver(onFulfilled(...args)))
    return nextPromise
  }

  // We check if the result is a "thenable"; if so, we treat
  // it as an inner promise, otherwise we simply fulfil with 
  // the result.
  const resolve = result => result?.then ? result.then(fulfil) : fulfil(result)

  // When a promise has been fulfilled, its "thens" can be run.
  const fulfil = result => (status = "fulfilled", value = result, executeThens(value))

  // "Thens" are run asynchronously, on a microtask.
  const executeThens = value => queueMicrotask(() => thenQ.forEach(el => el(value)))

  // The executor is run synchronously.
  executor(resolve)

  return {
    then,
    get status() { return status },
    get value() { return value }
  }
}

// Chaining
new Promise(resolve => {
  console.log('Waiting for step 1...')
  setTimeout(() => resolve("One, two..."), 1500)
})
.then(result => new Promise(resolve => {
  console.log('Waiting for step 2...')
  setTimeout(() => resolve(`${result}three, four`), 1500)
}))
.then(result => console.log(`Chaining result: ${result}.`))

// Branching
const p = new Promise(resolve => {
  console.log('Waiting for step a...')
  setTimeout(() => resolve("Alpha, Bravo..."), 1500)
})

p.then(result => new Promise(resolve => {
  console.log('Waiting for step b1...')
  setTimeout(() => resolve(`${result}Charlie, Delta`), 1500)
})).then(console.log)

p.then(result => {
  console.log('Waiting for step b2...')
  return `${result}Echo, Foxtrot`
}).then(console.log)

See also.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
1

I'll go through your code in the order of execution.

At all times the value of this is whatever it was at the beginning. That's because you're only using arrow functions. But that's not relevant since you're not referencing this.

Main Code

let myPromise = new Promise(executor); creates a pending promise object. While creating the promise, the executor function will be executed.

setTimeout(callback, 1500); puts the callback function on some internal timer queue. The javascript engine promises to do its best to execute callback after (at least) 1500ms.

let a = 10; sets the variable a to 10.

myPromise.then(onFulfilled); creates another pending promise. It is linked to myPromise so that onFulfilled will be scheduled asynchronously when myPromise is fulfilled.

console.log(a); prints the value of a which is 10.

For the next 1500ms nothing happens. Then callback gets executed.

callback of setTimeout

console.log(getIDs); prints getIDs. From the name you can guess it's a function. So something like [Function: getIDs] will be printed.

resolve(10); fulfills myPromise and sets its result to 10. Since myPromised is now fulfilled, onFulfilled of anotherPromise gets scheduled asynchronously.

Now we have to wait for the call stack to process. After that, onFulfilled will be called.

onFulfilled of myPromise.then

console.log(val); prints the content of val. That is, the result of myPromise.

Robert
  • 2,603
  • 26
  • 25
  • 1
    The executor function is run immediately and synchronously. – Ben Aston Apr 27 '20 at 10:38
  • @BenAston You're right. Also the callback doesn't have access to resolve. Now.. that makes things a bit more difficult to structure. – Robert Apr 27 '20 at 14:15
  • @BenAston and Robert when program comes to this line let newPromise = myPromise.then(callback) when main code is running Is then method called there ? because new promise refernce saved in the newPromise variable i assume that then method called there and it return promise which refernce save in newPromise but the handler attached with it called asyncronously – javascript lover Apr 29 '20 at 05:51
  • @javascriptlover The function given to `.then` is never called immediately. The the whole point of `.then` is to wait for `myPromise` to resolve. And even if `myPromise` had already been fulfilled, the function given to `.then` would still run asynchronously to ensure consistency. – Robert Apr 29 '20 at 11:01
  • @Robert let newPromise = myPromise.then(callback) console.log (newPromise) // Promise why it is not undefined and how new promise reference store in newPromise variable. – javascript lover Apr 29 '20 at 11:33
  • @javascriptlover `.then` creates a new promise. `callback` is only executed after `myPromise` is fulfilled. The argument of `callback` is the result of `myPromise`. The return value of `callback` decides if `newPromise` will be fulfilled or rejected. That way you can create a whole chain of promises by `myPromise.then(callback1).then(callback2)` where `callback2` will only be called once `myPromise` got fulfilled and `callback1` also didn't result in a rejection. – Robert Apr 29 '20 at 13:27
  • @Robert i got it. – javascript lover Apr 29 '20 at 14:24