title: Is it true that the JavaScript ES6 promise has a standard procedure for then() to chain several time-consuming promises with asynchronous tasks?
body: <p>I think the short version of the question is: if the fulfillment handler supplied to a <code>.then()</code> returns a new promise, how does this new promise "unwrap" to the promise returned by <code>.then()</code>?  (unwrap seems like a terminology used in the promise technology). (and if it is not returning a new promise but just a "thenable", how does it unwrap?)</p>
  
  <p>To chain several time-consuming asynchronous promises together, such as <a href="https://javascript.info/promise-chaining#bigger-example-fetch" rel="nofollow noreferrer">doing several network fetches described on this page</a> or <a href="http://jsfiddle.net/qeg4Lwdv/" rel="nofollow noreferrer">a series of animations</a>, I think the standard method is stated as:</p>
  
  <blockquote>
    <p>In the fulfillment handler passed to <code>.then()</code>, create and return a new promise <code>p</code>, and in the executor passed to the constructor that created <code>p</code>, do the time-consuming task, and resolve this new promise <code>p</code> when done.</p>
  </blockquote>
  
  <p>Sometimes I may take this as: this is just the way it is (how to chain time-consuming promises), or it is the language feature, and you can just considered it to be happening by magic (if it is a language feature).</p>
  
  <p>But is it true that this is done by standard procedure how it would be handled if the fulfillment handler returns a new promise?</p>
  
  <p>I wrote out some rough draft of how it could be done below.  And to state it in a few sentences, it is</p>
  
  <ol>
  <li><code>p1</code> is the first promise.</li>
  <li><code>then()</code> returns a new promise <code>p2</code></li>
  <li>the <code>then()</code> remembers what <code>p2</code> is, as an internal property of <code>p1</code>.</li>
  <li>when the fulfillment handler passed to <code>then</code> eventually get invoked (when <code>p1</code> is resolved), the returned value is examined. If it is an object that has a property named <code>then</code> and is a function, then this object is treated as a thenable, which means it can be a genuine promise or just a dummy thenable (let's call it <code>p1_New</code>).</li>
  <li>Immediately, this is invoked: <code>p1_New.then(() =&gt; { resolveP2() })</code></li>
  <li>Let's say <code>p1_New</code> is a genuine promise. When we resolve <code>p1_New</code>, it will resolve <code>p2</code>, and <code>p2</code> will perform its "then" fulfillment handler, and the series of time-consuming promises can go on.</li>
  </ol>
  
  <p>So this is the rough draft of code:</p>
  
  <pre class="lang-js prettyprint-override"><code>let p1 = new Promise(function(resolve, reject) {
      // does something that took 10 seconds
      resolve(someValue);
  });
  </code></pre>
  
  <p>After the above code, the state of <code>p1</code> is:</p>
  
  <pre class="lang-js prettyprint-override"><code>p1 = {
    __internal__resolved_value: undefined,
    __internal__state: "PENDING",
    __internal__executor: function() {    
      // this is the executor passed to the constructor Promise().
      // Something is running and the resolve(v) statement probably
      // will do
      // this.__internal__onResolve(v)
    },
  
    __internal__onResolve: function(resolvedValue) {
  
      if (this.__internal__then_fulfillHandler) {   // if it exists
        let vFulfill = this.__internal__then_fulfillHandler(this.__internal__resolved_value);
  
        // if the fulfillment handler returns a promise (a thenable),
        // then immediately set this promise.then(fn1)
        // where fn1 is to call this.__internal__resolveNewPromise()
        // so as to resolve the promise newPromise that I am returning
  
        if (vFulfill &amp;&amp; typeof vFulfill.then === "function") { // a promise, or thenable
          vFulfill.then(function() {
            this.__internal__resolveNewPromise(this.__internal__resolved_value)
          })
        }
      }
  
    },
  
    // in reality, the then should maintain an array of fulfillmentHandler
    //   because `then` can be called multiple times
  
    then: function(fulfillmentHandler, rejectionHandler) {
      this.__internal__then_fulfillHandler = fulfillmentHandler;
  
      // create a new promise newPromise to return in any case
      let newPromise = new Promise(function(resolve, reject) {
        this.__internal__resolveNewPromise = resolve;
      });
  
      // if promise already resolved, then call the onResolve 
      //   to do what is supposed to be done whenever this promise resolves
      if (this.__internal__state === "RESOLVED") {
        this.__internal__onResolve(this.__internal__resolved_value);
      }
  
      return newPromise;
    }
  }
  </code></pre>
  
  <p>and that's how when <code>p1_New</code> is resolved, then <code>p2</code> is resolved, and the fulfillment handler passed to <code>p2.then()</code> will go on.</p>
  
  <pre class="lang-js prettyprint-override"><code>let p2 = p1.then(function() {
    p1_New = new Promise(function(resolve, reject) {
      // does something that took 20 seconds
      resolve(someValue);
    });
    return p1_New;
  });
  
  p2.then(fulfillmentHandler, rejectionHandler);
  </code></pre>
  
  <p>But <a href="https://javascript.info/promise-chaining" rel="nofollow noreferrer">what if <code>p1_New</code> is not really a promise, but just a dummy <code>thenable</code></a> written this way:</p>
  
  <pre class="lang-js prettyprint-override"><code>class Thenable {
    constructor(num) {
      this.num = num;
    }
    then(resolve, reject) {
      alert(resolve); // function() { native code }
      // resolve with this.num*2 after the 1 second
      setTimeout(() =&gt; resolve(this.num * 2), 1000); // (**)
    }
  }
  
  new Promise(resolve =&gt; resolve(1))
    .then(result =&gt; {
      return new Thenable(result); // (*)
    })
    .then(alert); // shows 2 after 1000ms
  </code></pre>
  
  <p>it is doing the time-consuming task in its <code>then()</code>. That's fine too: if we look at step 5 above:</p>
  
  <ol start="5">
  <li>Immediately, this is invoked: <code>p1_New.then(() =&gt; { resolveP2() })</code></li>
  </ol>
  
  <p>that is, <code>then</code> is invoked immediately, and with the first function passed in being able to resolve <code>p2</code>. So that <code>thenable</code> performs some time-consuming task, and when done, call its first parameter (the function that resolves <code>p2</code>), and the whole sequence can go on like before.</p>
  
  <p>But in this case, it is the <code>then()</code> doing the time-consuming task, not the executor doing it (the executor passed to the constructor of a new promise). In a way, it is like the <code>then()</code> has become the executor.</p>