Javascript promise chaining then no wait the previous then finished

<script>
function myDisplay2() {
	  let myPromise = new Promise((resolve, reject)=>{			
			resolve(1);})  
	  let myPromise2 = myPromise.then(setTimeout(()=>{
			console.log(myPromise);   // first then()
			return new Promise((resolve, reject)=>{		
			resolve(2);});
	  }, 10000));
	  let myPromise3 = myPromise2.then(()=>{console.log(myPromise2)});  // second then()
}

myDisplay2();
</script>

https://i.postimg.cc/6QqcPk17/promise-Problem2.jpg

I use setTimeout to simulate an asynchronous call.
In the console, the output is second then() run first, and the PromiseResult is 1, then first then is run, PromiseResult is 1 also.

  1. why second then() is run before first then() is resolved?
  2. how to modify to make second then() run after first then() is resolved?

you’ve got promise2 a bit inside out.

  let myPromise2 = myPromise.then(setTimeout(()=>{
		console.log(myPromise);   // first then()
		return new Promise((resolve, reject)=>{		
		resolve(2);});
  }, 10000));

Should be

	  let myPromise2 = myPromise.then(() => { 
            return new Promise((resolve,reject) => { 
              setTimeout(()=>{
	            console.log(myPromise);
                resolve(2);
	          }, 10000)
            });
       });

The then statement needs to return a new Promise immediately (well, at the end of its processing, but you get what i mean), if its going to, so that the next then knows what to wait for.

1 Like

yes, following your change, the output is first then () run first, and second then() will run after first then().
But is this really necessary that then() statement needs to return a new Promise immediately? As its API has not mentioned such requirement.

setTimeout has no return and is asynchronous, so there is no difference between

mypromise.then(() => {
  setTimeout(.....)
}

and

mypromise.then(() => {
  console.log("a thing");
}
1 Like
  1. no difference between
mypromise.then(() => {
  setTimeout(.....)
}

and

mypromise.then(() => {
  console.log("a thing");
}

so…what is the consequence? I cannot catch your idea…or you mean my origin code, setTimeout() has no return type and so nothing to wait for return?

  1. why the then() API in
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
    has not mentioned then() statement needs to return a new Promise immediately?

Just to clarify setTimeout only returns an identifier number, which can then be used with clearTimeout() to cancel that timed event.

1 Like

so…yes, setTimeout returns an identifier which can be used to clear the timer.

The important concept is that setTimeout is effectively an asynchronous call. In the strictest terms, it’s not - the thread stops, and waits for setTimeout to return a value - but that value (the identifier) is returned near instantaneously, and the thread continues. It DOES NOT wait for the timer to expire and retrieve the result from the called procedure.

So… my example may have been slightly off. It’s not equivalent to console.log, it’s equivalent to var x = 3;. Is everybody happy now with what type of thing gets spit out of a null-effect statement?

This return IS specified in the MDN:

For the purposes of timing, an uncaught and unreturned setTimeout is a no-op. So your script as originally written for mypromise.then goes:

Wait for myPromise to Resolve or Reject.
NoOp;
Return Promise(resolve(undefined))

If you had return'd the setTimeout, you’d have returned the value of the handle, and the MDN specifies that:

What you are trying to do, and what is also spelled out in the MDN, is the last return rule:

It has to evaluate these rules when the thread leaves the function. Because setTimeout does not halt the thread (except for the microsecond or so it spends figuring out what the handle is), it is immediate, and must be evaluated at that time.

2 Likes

quite lost, “setTimeout is effectively an asynchronous call”, chaining then() is not used to force one asynchronous call inside then() finished before the next then()?
Inside the first then() is a asynchronous call (setTimeout()), why the second then() not wait it finished?

A couple of articles that might be helpful Tong

https://medium.com/javascript-in-plain-english/javasscript-promises-and-the-micro-task-queue-6111f7452f05

https://medium.com/@sadia.islam.badhon/callback-queue-vs-microtask-queue-9dc6a790330e

The rough gist of it. setTimeout and promise callbacks end up on two different queues. setTimeouts on the callback queue and promises on the microtask queue. The event loop prioritizes microtask queued callbacks over the callback queue’s.

1 Like

I believe “async” and “await” will solve this problem.
They are also far easier to understand and chain together; plus they have other additional capabilities.

You can’t await a setTimeout - it returns a value immediately (the handle), so there’s nothing to wait for.
You could sleep(10000) though, sure, if you don’t mind your main javascript thread being held up in the meantime, which is sort of what Promises were designed NOT to have to do.

Await says “Normally, I set this thing going and forget about it. But now i’ll wait for it to come back and see what it says.”

A Promise is “I’m setting this thing going, but whenever it gets done, I want to know about it, because I have things to do.”

setTimeout is “I want to do some things at a fixed time from now.”

Similar, but all slightly different.

1 Like
let myPromise3 = myPromise2.then(()=>{console.log(myPromise2)});  // second then()

before setTimeout(…,10000) is returned, myPromise2 is neither resolved nor rejected, right? but still will run myPromise2.then()?

Or my origin sample is this case? it returns a value immediately (the handle), and the first then() “gets resolved immediately with the returned value (the handle) as its value”? but if this is the case, the second then() (the value of myPromise2) should return the handle value, not 1…

no, because setTimeout returns handleX to your function, and your function shrugs and exits, because you didnt tell it to return the value.

.then(
setTimeOut(...)
)

returns nothing.

.then(
return setTimeOut(...)
)

returns the handle.

1 Like
  1. then my origin question case is the same as the following mentioned in MDN?

If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state ( fulfillment or rejection ) for which then has no handler, the returned promise adopts the final state of the original Promise on which then was called.

“the Promise that then is called on " is myPromise in my quesiton. " the returned promise adopts…” is myPromise2 in my quesiton?

  1. And the “gets resolved with an undefined value.” is happened immediately?

Right, so what this is saying is:

then takes two parameters: a function to execute when the result of the promise it’s called upon was a success, and a function to execute when the result of the promise it’s called upon was a failure.

In the below example, we do not generate/define a function for the failure state.
mypromise.then(() => { var x = 3; doSomeStuff(x); })

if mypromise is resolved , then executes the function we have defined, and returns a new Promise that satisfies the rules listed in MDN, depending on the return value of our function (in this case, it would be a resolved Promise with value undefined)

if mypromise is reject'd, there is no function defined to handle the rejection (there is no second parameter in our then), so then returns a new, reject'd, Promise, with whatever value was in the rejection from mypromise (In other words, it propagates the rejection)

correct. var x = myPromise.then(), myPromise is the “promise the then is called on” and x, after execution, will contain the ‘returned promise’.

If the promise would be resolved , it would be immediate. (All rules return a resolved promise, with the exception of the one that returns a pending promise.)