admin管理员组

文章数量:1316829

I have read We have a problem with promises by Nolan Lawson for a few times, but still have some questions about promises in JavaScript. At the end of Nolan's post you can find answers for four puzzles (I've attached screenshots here).

So, I have a few questions:

  1. Why does doSomethingElse() function in the 1st puzzle have undefined value? To my mind, it must have resultOfDoSomething like in the 4th puzzle.

  2. What's the difference between the 3rd and 4th puzzles? In the 3rd puzzle in the first then we write doSomethingElse() and in the 4th puzzle we write here only the name of function, doSomethingElse. How is it possible? What does really doSomethingElse do inside the then of the 4th puzzle?

  3. Why does doSomethingElse() function in 3rd puzzle start at the same moment as doSomething?

I have read We have a problem with promises by Nolan Lawson for a few times, but still have some questions about promises in JavaScript. At the end of Nolan's post you can find answers for four puzzles (I've attached screenshots here).

So, I have a few questions:

  1. Why does doSomethingElse() function in the 1st puzzle have undefined value? To my mind, it must have resultOfDoSomething like in the 4th puzzle.

  2. What's the difference between the 3rd and 4th puzzles? In the 3rd puzzle in the first then we write doSomethingElse() and in the 4th puzzle we write here only the name of function, doSomethingElse. How is it possible? What does really doSomethingElse do inside the then of the 4th puzzle?

  3. Why does doSomethingElse() function in 3rd puzzle start at the same moment as doSomething?

Share Improve this question edited Oct 28, 2015 at 10:20 sdgluck 27.3k12 gold badges81 silver badges95 bronze badges asked Oct 27, 2015 at 20:13 Vlad TurakVlad Turak 6,3744 gold badges25 silver badges26 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 3
  1. Why does doSomethingElse() function in 1st puzzle [get passed] undefined?

Let us look at a simpler example:

foo();   // Line #1
foo(42); // Line #2

The difference between the two lines is what? On line #1, we are calling foo but passing it no value (hence undefined) whereas on line #2 we are calling foo and passing it 42.

Going back to the post:

doSomething().then(function () {
    return doSomethingElse( );
    //                     ^-- we are not passing a value
}).then(finalHandler);

How is this different to the 4th puzzle? In the 4th puzzle we are passing a reference to the function to then. Giving the promise the reference to the function allows it to call it at a later time with the result of the promise.[1]


  1. What's the difference between the 3rd and 4th puzzles? In the 3rd puzzle [...] we write doSomethingElse() and in the 4th puzzle we write [...] doSomethingElse.

To explain the differences in the 3rd and 4th puzzles, let's look at simpler examples. How do the following two lines differ:

var foo = function foo() {
    return 42;
};
var a = foo;   // line #1
var b = foo(); // line #2

In the snippet above, a will contain a reference to the function foo whereas b will contain the result of calling foo (which would be 42).


  1. Why does doSomethingElse() in the 3rd puzzle start at the same moment as doSomething?

Similar to the differences between the 3rd and 4th functions, note the use of () to invoke (or call) the function. Here we are calling both doSomething() and doSomethingElse() instead of waiting for the promise to "resolve" (waiting for the first call to finish). before Let us step through the execution:

  1. Execute doSomething which returns a Promise
  2. Attach the doSomethingElse() to the promise—but wait, doSomethingElse() is us calling doSomethingElse(), so that will happen async and we will attach the promise it returns to the promise doSomething() returned.
  3. Attach the function finalHandler to the promise

Long story short - simple 2 rules to make your examples understandable:

  1. Returning a value from inside .then is the same as returning a promise that resolves with that value.

  2. When you return nothing, it is the same as returning undefined, which in turn enacts rule #1.

If you keep these 2 in mind, your promise puzzles bee clear as day.

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

Why does doSomethingElse() function in 1-st puzzle have undefined value? To my mind, it must have resultOfDoSomething like in 4-th puzzle.

The promised result of doSomething is passed to the anonymous function (which doesn’t even accept an argument). So whatever is passed there is lost. And doSomethingElse is called without any arguments, so the first function argument is undefined.

doSomething().then(doSomethingElse());

doSomething().then(doSomethingElse);

What's the difference beetwen 3-rd and 4-th puzzles? In 3-rd puzzle in first then we write doSomethingElse() and in 4-th puzzle we write here only the name of function - doSomethingElse. How is it possible? What does really doSomethingElse do in then of 4-th puzzle?

Functions in JavaScript are objects which you can pass around as you like. That’s actually how the whole callback passing works: There is a function (here, it’s then) that takes a function as a parameter which is then later called.

So in the latter code, the function that is passed to then is doSomethingElse so that is the function which is later called. But in the former, we call doSomethingElse directly (with the parentheses ()). So what gets passed to then is the return value of that function—which is unlikely a function that can be evaluated once the promise pletes.

Why does doSomethingElse() function in 3-rd puzzle start at the same moment as doSomething?

As I said, the function is immediately called, at the same time you call doSomething. Only the return value is passed to then which would then be called once the promise resolves.

You must pay attention: doSomethingElse is a function reference while doSomethingElse() means that you "call" the function right away. Here you can get the result of the function, if any...

About promises I understood that:

A) The "then" method takes the result of the previous call and pass it as parameter to its own parameter if it is a function.

B) The execution is delayed only if the function inside the "then" method returns something.

In these situations we have:

Puzzle 1) resultOfDoSomething is used as parameter for the anonymous function

function (){ return doSomethingElse ();} 

This calls doSomethingElse() without parameters.

Puzzle 2) the anonymous function does not return data so the next "then" is immediately executed

Puzzle 3) the expression doSomethingElse() is the result of the call of doSomethingElse. This value is used as parameter for the "then" method and since it is not a function (in this example!), we can pass to the other "then"...

finalHandler receives the last valid results as parameters, in this case resultOfDoSomething.

Puzzle 4) every "then" method receives as parameter the reference of a function. Each one of these functions will be called with the previous results as parameters. So, every function MUST wait for the result of the previous execution... and here you have the queue of the promises...

Why does doSomethingElse() function in the 1st puzzle have undefined value? To my mind, it must have resultOfDoSomething like in the 4th puzzle.

Nope. The resultOfDoSomething is passed to the callback that then was called with, yes, but we're simply ignoring it in the first code:

doSomething().then(function(resultOfDoSomething) {
//               it's here: ^^^^^^^^^^^^^^^^^^^
    return doSomethingElse(  );
//          but not there: ^^ - Ooops!
});

What's the difference between the 3rd and 4th puzzles? In the 3rd puzzle in the first then we write doSomethingElse() and in the 4th puzzle we write here only the name of function, doSomethingElse. How is it possible? What does really doSomethingElse do inside the then of the 4th puzzle?

As you probably know, it's the difference between a called function and the function itself.

Also, we always want - no: must - pass a callback function to then(…). The following two are equivalent:

promise.then(function callback(res) {
    …
});
function callback(res) {
    …
}
promise.then(callback);

That's expected - you pass a function to the call, so it is chained onto the promise as usual. But callback() (with the invocation) is not a function any more:

Why does doSomethingElse() function in 3rd puzzle start at the same moment as doSomething?

Because it is called immediately in the expression then(doSomethingElse()) - it is in fact called before then, to which it is an argument. So it is in fact called a moment after doSomething(), but on the same event loop turn; and the two asynchronous somethings will run in parallel.

Also, then does only accept function arguments, everything else is ignored. So there is no chaining going on here, it's the same as doing

var promise = doSomething();
doSomethingElse();
promise.then(finalHandler);

Not what we want!

Btw, these are also explained as "Advanced mistake #3: promises vs promise factories" and "Advanced mistake #5: promises fall through", which I both would consider as rookie mistakes :-)

I think the execution order of is always first doSomethingElse then doSomethingElse and finalHandler. This is just JavaScript syntax.

Difference is that the args pass to function are different.

The two functions return two promises.The two promises execution order is show in figures you posted. I think the author means the order of two promises not the function execution order.

/**
 * Created by tshungle on 17-2-24.
 */
'use strict'
function doSomething() {
  console.log("doSomething start");
  sleep(1000)
  console.log("doSomething end");
  return new Promise(function (resolve, reject) {
    setTimeout(function() {
      console.log("Promise of doSomething is about to resolve");
      resolve("doSomething resolvation")
    }, 2500);
  });

}

function doSomethingElse() {
  console.log("doSomethingElse start");
  sleep(1000);
  console.log("doSomethingElse end");
  return new Promise(function (resolve, reject) {
    setTimeout(function() {
      console.log("Promise of doSomethingElse is about to resolve");
      resolve("doSomethingElse resolvation")
    }, 2500);
  });
}

function finalHandler(result) {
  console.log("finalHandler result is:", result);
}

function sleep(ms) {
  var stop = new Date().getTime();
  while(new Date().getTime() < stop + ms) {
    ;
  }
}


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

//2
// doSomething().then(function () {
//   doSomethingElse();
// }).then(finalHandler);
//
//3
// doSomething().then(doSomethingElse())
//   .then(finalHandler);

//4
// doSomething().then(doSomethingElse)
//   .then(finalHandler);

本文标签: Nolan39s PromisesA JavaScript puzzlesStack Overflow