A walk through of displayAll's order of execution:
-
var myPromise = (new Promise(display1))
The Promise constructor calls display1 which sets up a timeout to log "display1" and resolve the promise. This works perfectly and the initial 1 second delay is honored.
-
.then(new Promise(display2))
- calls the
then method of myPromise during execution of displayAll.
- The argument for
then is evaluated before the making the call .
- Creating
then's promise argument causes the Promise constructor to call display2 which sets up a timeout relative to displayAll's time-of-execution.
- When called
then silently ignores the promise argument because it's not a function. Default handlers, used by then in the absence of callable arguments, pass through incoming data or promise rejection reasons.
-
.then(new Promise(display3))
operates the same as the previous then clause: set up a timer relative to displayAll's time-of-execution and use default handlers which pass through data or rejection reasons.
-
.then(display4)));
registers display4 as a handler to be called when the promise returned in step 3 becomes fullfilled. display4 sets up a workable timer to log "display4". Note display4's argument is now misnamed - the argument passed to successive fulfillment handlers is the value returned by the previous promise handler in the chain.
The expected output of calling displayAll is then to
- Delay a second after
displayAll was called and log "display1".
- Delay a second, again after
displayAll was called, and log "display2".
- Delay a second, again after
displayAll was called, and log "display3".
- When promise chain handling executes
display4 as a handler, set up a timer to log "display4" - so it logs one second after "display3".
One solution to stagger the execution of the display functions would be to move promise creation from where then arguments are calculated into the handler itself. The handler can return the promise to delay proceeding down the promise chain until the returned promise is resolved by the timer:
function displayN() {
return new Promise( resolve =>
setTimer( function() {
console.log("displayN");
resolve();
}, 1000)
);
}
Other solutions and approaches are possible. Promisifying setTimeout to create a promise that resolves after a specified interval can be useful for delaying steps in a promise chain or async function. As a fairly minimal example:
function delayPromise( msec) {
return new Promise(resolve=> setTimeout( resolve, msec));
}
As an aside only, the value of a promise chain is the promise returned by the last then, catch or finally call in the chain - promise chain values may be returned by a function but in practice at least are rarely recorded in a variable.