Skip to content

Instantly share code, notes, and snippets.

@nolanlawson
Last active July 26, 2022 08:02
Show Gist options
  • Star 53 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save nolanlawson/940d1a390b2d9cf9483c to your computer and use it in GitHub Desktop.
Save nolanlawson/940d1a390b2d9cf9483c to your computer and use it in GitHub Desktop.
Promises puzzle cheat sheet

Promises puzzle answer sheet

Solution to https://twitter.com/nolanlawson/status/578948854411878400.

Puzzle #1

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

Answer:

doSomething
|-----------------|
                  doSomethingElse(undefined)
                  |------------------|
                                     finalHandler(resultOfDoSomethingElse)
                                     |------------------|

Puzzle #2

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

Answer:

doSomething
|-----------------|
                  doSomethingElse(undefined)
                  |------------------|
                  finalHandler(undefined)
                  |------------------|

Puzzle #3

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

Answer:

doSomething
|-----------------|
doSomethingElse(undefined)
|---------------------------------|
                  finalHandler(resultOfDoSomething)
                  |------------------|

Puzzle #4

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

Answer:

doSomething
|-----------------|
                  doSomethingElse(resultOfDoSomething)
                  |------------------|
                                     finalHandler(resultOfDoSomethingElse)
                                     |------------------|
@scottnonnenberg
Copy link

It's a bit hard to tell, because doSomethingElse isn't defined.

In #1 and #2 it looks like we assume that it's a function that returns a promise. And in #2 we learn the lesson of not passing a promise back at the end of all callbacks passed to then().

In #3, if it returns a function that returns a promise, then its chart will look like the chart for #4.

In #4 we are again assuming that it's a function that returns a promise, otherwise doSomethingElse and finalHandler will be overlapped.

Whew!

Copy link

ghost commented Jan 23, 2016

Nice set of questions Nolan. I was spending a lot of time on Promises. Here is my take.
Can you please let me know if these are correct?


/* Revising the basics. Here we have three promises P1,P2,P3. 'then' actually takes a value transformer 
 * function so that can transform P1's value and use that to settle P2. This code will be in
 * the resolve function of P1. It would look something like transformed = transform(value)
 * resolve(transformed). 'resolves' are bound function of a promise so each
 * resolve will be assosiated with one and only one Promise.
 * PS: Currently not assuming doSomething else itself returns promise P`, in which case the caller will adopt its state
 * and attach its resolve to P` then. When P` is done it will resolve the caller with that value and continue as before.  
 */

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

/* Here transformer doesn't accept input i.e ideally P1's value so after the promise has 
 * been resolved it would just execute the doSomethingElse() and return its 
 * value to P1 and settle P2. P2 will be settled with doSomethingElse. P3 can
 * potentially be settled by P2 by using finalHandler(transformed). A clear
 * drawback is that the P1's value wouldn't be used at all in this case.
 */

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

/* Here transformer accepts nothing and returns nothing. Hence doSomethingElse
 * will be just used for side effects. P2 will be resolved with 'undefined'. P3
 * can be settled by P2's transformer with 'undefined' value. This is not meant
 * to be done using Promise ideally.
 */

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

/* 'then' accepts a function, so iere if we assume doSomethingElse() is a function
 * and if that function can accept a value, it can continue as below.
 */

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

/* This is best of all the scenarios in the sense that if doSomethingElse is a
 * function that accepts value it can be used to transform the value of P1 and the
 * transformed value will settle P2. finalHandler(transformed) will be used to
 * settle P3.
 */

@royling
Copy link

royling commented Aug 3, 2016

The graph answer for #3 is not accurate, @scottnonnenberg is right:

In #3, if it returns a function that returns a promise, then its chart will look like the chart for #4.

@derekgreer
Copy link

Understanding these puzzles correctly requires an assumption that doSomething() and doSomethingElse() return promises. @scottnonnenberg is correct that if doSomethingElse() returned a function then the results listed for puzzle #4 would be expected for #3. Since doSomethingElse() returns a promise and not a function that returns a promise, however, the then() function treats the promise parameter as a null and the value therefore falls through to the finalHandler. This threw me as well given I arrived at this gist prior to reading the associated blog article: https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html.

@anfedorov
Copy link

it's called doSomething not doSomethingAndReturnPromise. duuuh!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment