3

I'm currently learning the javascript promise.

I have been taught that if an object/function contain a member function named then(..) on itself, then the object/function will be recognised as a promise like object, regardless whether the object/function is a true promise object or not.

So I have come up with the following code.

var aPromise = new Promise(function (resolve, reject){});
aPromise instanceof Promise; //prints true in chrome console


var a = {
    then: function(){}
};

a instanceof Promise;

But after a instanceof Promise is executed in chrome console, false was printed.

Why is this happening? Am I doing something wrong or my understanding of what is a promise-like object is incorrect?

Thor
  • 9,638
  • 15
  • 62
  • 137
  • 3
    “Promise-like object” means that despite it *not* being the case that `a instanceof Promise`, `a` can be treated like a promise. – Ry- Aug 29 '17 at 02:16
  • 1
    I think what it means is that it will act like a promise, but is not necessarily an instance of it. As in it behaves like one, but is still literally just an Object. – notphilphil Aug 29 '17 at 02:17
  • 2
    `it will act like a promise` - hopefully, because there's no guarantee that a `.then` function has to do anything promise like :p – Jaromanda X Aug 29 '17 at 02:20
  • please correct me if I'm wrong, but my current understanding is that `a instance Promise` by itself it enough to determine whether a object is a real `Promise` object (i.e. return `true` for objects that are true `Promise` object) or a `Promise-like object` (i.e. return `false` for objects that has a `then` function on it, and can be used as a promise object, but is not a true Promise object) – Thor Aug 29 '17 at 02:21
  • 1
    anything not a Promise will result in `a instance Promise` being false ... even those without a `.then` ... `instanceof` does not care about thenables – Jaromanda X Aug 29 '17 at 02:27
  • thanks everyone for the clarification! now everything starts to make sense :) – Thor Aug 29 '17 at 02:27
  • 1
    instanceof as the name implies tests if an object is an instance of some constructor function. Since your `a` was not created by the Promise constructor function, nor a function that inherited from it then it is not an instance of it. If you wanted to test "promise like" or "thenable" then test for `then`, `if('then' in a)` – Patrick Evans Aug 29 '17 at 02:28
  • 1
    I never thought of duck-typing as "ducking type" before but thats an interesting take on it :) – chiliNUT Aug 29 '17 at 02:40
  • 1
    Have a look at [what is the difference between the terms “thenable” and “promise”?](https://stackoverflow.com/q/29435262/1048572) and maybe also [decide if object or promise](https://stackoverflow.com/q/43033988/1048572) – Bergi Aug 29 '17 at 02:50

4 Answers4

2

A. instanceof

Technically, the Javascript expression a instanceof b checks

  • a is an object (which includes functions because they are objects),
  • 'b' is a constructor function - which includes classes because declarations and expressions using the class keyword create constructor functions,
  • the value of b.prototype is in the inheritance chain of a. This means either a was constructed by b, or otherwise somewhere in the inheritance chain of a there is an object constructed by b.

Given an objects inheritance chain is set to the prototype property of its constructor, aPromise in your code is an instance of Promise because Promise.prototype is the first entry in its prototype chain. The second entry in its prototype chain is Object.prototype so aPromise is an instance of Object as well.

a is constructed and initialized by Object in response to the {..} object initializer syntax. Object.prototype is the first object in its inheritance so its an "instance of" Object and nothing else.

B. Thenable objects

"Thenable" objects, with a .then method, are described in the A+ promise specification on which ES6 promises are based.

Recognition and treatment of thenables allow different software libraries, each using its own Promise constructor code, to deal with promises created by another library created using a different constructor. Simply checking if a promise object is an instance of a library's own "Promise" constructor prevents inter-library usage of promise objects.

The one time a promise implementation needs to deal with a "thenable" object, is when a foreign library promise is used to resolve a promise created by an implementation. The standard method of dealing with this is for the implementation to create a new pair of resolve/reject functions, say resolve2 and reject2 for the promise being resolved, and call the thenable's then method to pass on it's settled value. In pseudo code:

if promiseA, instance of PromiseA, is resolved with promiseB, instance of PromiseB {

    PromiseA code creates new resolve2/reject2 functions for promiseA
    and calls the thenable's then method as:

         promiseB.then( resolve2, reject2);
}
// ....
If promiseB remains pending, promiseA remains pending;
If promiseB is settled, promiseA becomes fulfilled or rejected with the same value.
Community
  • 1
  • 1
traktor
  • 17,588
  • 4
  • 32
  • 53
2

Use the method Promise.resolve to convert your thenable object ('a') into a Promise:

var a = Promise.resolve({
    then: function(){}
});
1

The instanceof operator tests whether an object in its prototype chain has the prototype property of a constructor.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof

This is unrelated to (maybe even the opposite of?) duck typing, wherein an object's methods and properties determine the symantics of the object, thereby allowing you to treat it like you might treat a Promise, but it in no way makes it an instance of or descendant of a Promise.

(emphasis added by me)

In computer programming with object-oriented programming languages, duck typing is a style of typing in which an object's methods and properties determine the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface.

https://en.wikipedia.org/wiki/Duck_typing via https://ericlippert.com/2014/01/02/what-is-duck-typing/

A concrete example in javascript is the nodeList; it is array-like because you can access members of a node list by an integer index, but it is not an array, nor an instanceof an array.

chiliNUT
  • 18,989
  • 14
  • 66
  • 106
1

If you want to check for a thenable (Promise like) object

if ((typeof a === 'function' || typeof a === 'object') && typeof a.then === 'function') {
    // a is "Promise like" (or a Promise)
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87