2

I have doSomething, doSomethingElse & finalHandler functions as following:

function doSomething() {
  console.log('doSomething(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('doSomething(): end');
      resolve();
    }, 1000);
  });
}

function doSomethingElse() {
  console.log('doSomethingElse(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('doSomethingElse(): end');
      resolve();
    }, 1000);
  });
}

function finalHandler() {
  console.log('finalHandler(): start');
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log('finalHandler(): end');
      resolve();
    }, 1000);
  });
}

I have a function example1 which looks like this:

function example1() {
  doSomething().then(function () {
    return doSomethingElse();
  }).then(finalHandler);
}

is returning

doSomething(): start
doSomething(): end
doSomethingElse(): start
doSomethingElse(): end
finalHandler(): start
finalHandler(): end

I have example2:

function example2() {
  doSomething().then(function () {
    doSomethingElse();
  }).then(finalHandler);
}

returning:

doSomething(): start
doSomething(): end
doSomethingElse(): start
finalHandler(): start
doSomethingElse(): end
finalHandler(): end

And example3:

function example3() {
  doSomething().then(doSomethingElse())
    .then(finalHandler);
}

returning:

doSomething(): start
doSomethingElse(): start
doSomething(): end
finalHandler(): start
doSomethingElse(): end
finalHandler(): end

And example4:

function example4() {
  doSomething().then(doSomethingElse)
    .then(finalHandler);
}

returning:

doSomething(): start
doSomething(): end
doSomethingElse(): start
doSomethingElse(): end
finalHandler(): start
finalHandler(): end

I can understand that different function calling syntax is giving different results - but what is the concept behind this behavior?

I am not looking for a correction or optimized code. I wanted to know how is the flow navigated with different syntax?

Zameer Ansari
  • 28,977
  • 24
  • 140
  • 219
  • 2
    "*one would have expected the following output only*" - uh, no, why would you have expected this? Do you know what `then` is all about? – Bergi Jun 27 '20 at 14:47

1 Answers1

1

The concepts in play here -

  1. Tasks is microtask queue will be exhausted at the end of one execution context, before picking tasks from macrotask queue.
  2. Callback of promise resolved is a microtask.
  3. Callback of setTimeout is a macrotask.
  4. Chained then will only wait for previous then, if the previous then retuns a promise. If it is anything apart froma promise, the next then will not wait for previous then.
  5. Passing a reference to a function is different then calling a function. for example1

doSomething() goes in call stack -> doSomething(): start printed it returns a promise which will be resolved after 1 sec and then the 'then' handler will be called. As there are no resolved promises or tasks, the program returns. You can verify with a undefined being printed if you execute in chrome. After 1 sec the first promise is resolved, the one queued in doSomething. As the statement console.log('doSomething(): end'); is sync, it gets printed.

.then(function () {
    return doSomethingElse();
  })

is executed now. Same flow as above- console.log('doSomethingElse(): start'); --> after 1 sec doSomethingElse end Same for the last then: console.log('finalHandler(): start'); --> after 1sec console.log('finalHandler(): end');

Example 2 is different from Example 1 in the sense that in the first example ,then gets returned a promise by doSomethingElse. The then chained after that will wait for that promise to be resolved before executng.But in example 2, even though doSomethingElse returns a promise , we are not not returning that in then handler callback, thats why event though doSomethingElse will be executed and the setTimeout will be set for doSomethingElse(): end, the then for final handler will be executed immediately, because it wont wait for the previous promise to be resolved. It would only have waited if previous then retuned a promise. hence the finalHandler(): start is printed first. After that both the timers for doSomethingElse timeout and finalHandler timeout expire, but the previous timeout will be be first in the task queue so it it gets printed first.

Regarding the different formats .. When you do .then(doSomethingElse) you are passing a reference to the function, so its same as you just copy the full code of doSomethingElse in then.then(). Its a valid callback. But when you do .then(doSomethingElse()) it just executes the function doSomethingElse, but its not a callback, so doesn't get any callback, it just gets undefined, and hence the next then in chain gets executed.

rest two examples should be self explanatory now.

Kamlesh Tajpuri
  • 482
  • 3
  • 11