3

According to MDN:

...if the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state;

This piqued my interest a bit, so I wanted to see if it was possible to re-implement this functionality in pure Javascript. What I ended up with is this:

function resolve(p){
    if (
        p !== null &&
        (
            typeof p === "object" ||
            typeof p === "function"
        ) &&
        typeof p.then === "function"
    ) {
        return p.then(
            function resolved(value){
                return new Promise( function (resolve, reject) {
                    resolve(value);
                });
            },
            function rejected(error){
                return new Promise( function (resolve, reject) {
                    reject(error);
                });
            }
        );
    }
    else {
        return new Promise( function (resolve, reject) {
            resolve(p);
        });
    }
}

So I tested this with a variety of values:

var a = new Promise (resolve => resolve("hello"));
var b = "hello";
var c = {
  then: onFulfilled => onFulfilled("hello")
};
var d = {
  then: onFulfilled => {
    onFulfilled("hello")
  }
}

Promise.resolve(a); //Promise {<resolved>: "hello"}
Promise.resolve(b); //Promise {<resolved>: "hello"}
Promise.resolve(c); //Promise {<resolved>: "hello"}
Promise.resolve(d); //Promise {<resolved>: "hello"}

resolve(a); //Promise {<resolved>: "hello"}
resolve(b); //Promise {<resolved>: "hello"}
resolve(c); //Promise {<resolved>: "hello"}
resolve(d); //undefined -- uh oh.

So obviously since d's then method doesn't return anything, the result is undefined... but if I am looking at this right, Promise.resolve() is extracting this value under the hood somehow? Is it automagically pulling out the return value of the onFulfilled function call? Or am I looking at this completely wrong?

Hans Tang
  • 33
  • 4
  • `then` resolves to the value returned by the callback. It did not return any in your `d` – Son Nguyen Jun 28 '20 at 11:26
  • Aye, but Promise.resolve() actually does cast d to a promise with a resolved "hello". Somehow it found the value despite d's then method never returning. I was just curious if my train of thought here is accurate. If the JS engine is doing something here outside the capabilities of the script, that's understandable. – Hans Tang Jun 28 '20 at 11:33

1 Answers1

4

Promise.resolve does not rely on the return value of the .then() invocation on the thenable value. It rather looks similar to this:

function resolve(v) {
    return new Promise((resolve, reject) => {
        if (Object(v) === v && typeof v.then === "function") {
            v.then(resolve, reject);
        } else {
            resolve(v); // fulfill (no recursive resolution)
        }
    });
}

This is usually known as the Promise constructor antipattern, but it's warranted when we cannot trust the then method. I recommend to take a look at how Promises/A+ specifies dealing with thenables.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375