Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

instanceof doesn't work for $q promises #13545

Closed
thorn0 opened this issue Dec 15, 2015 · 10 comments
Closed

instanceof doesn't work for $q promises #13545

thorn0 opened this issue Dec 15, 2015 · 10 comments

Comments

@thorn0
Copy link
Contributor

thorn0 commented Dec 15, 2015

angular.module('app', []).run($q => {
  var promise = new $q(resolve => resolve());
  console.log(promise instanceof $q); // false
});

http://plnkr.co/edit/a6VE6z

So basically there is no way to check if an object is a $q promise.

@lgalfaso
Copy link
Contributor

A promise can never be an instance of $q as that would imply that

  • a promise has a method named defer, reject...
  • $q has a method named then

When not sure if something is a promise or not, then the best option is to use $q.when

@thorn0
Copy link
Contributor Author

thorn0 commented Dec 15, 2015

No, in JS, "is instance of" doesn't mean what you have described. Angular introduced $q.resolve instead of $q.when for consistency with ES6, so it'd be logical to make instanceof work too since it works in ES6 (ES6 promises are instances of Promise).

@lgalfaso
Copy link
Contributor

$q follows Promises/A+ and this was based on Kris Kowal's Q. The first implementation of $q was well before ES6 Promise was a draft. It uses when and not resolve because that is what Kris Kowal's Q uses.

$q has some methods, these are specified at https://docs.angularjs.org/api/ng/service/$q and include defer, reject and others that currently are part of the $q prototype.

The object returned by $q.defer (that in the docs is referred as Deferred or Promise) has, in its prototype, the methods then, finally and catch.

Keeping things in the prototype reduces the memory pressure on something as critical as Promises.

With this information, can you please elaborate

No, in JS, "is instance of" doesn't mean what you have described.

@thorn0
Copy link
Contributor Author

thorn0 commented Dec 17, 2015

It seems like you're confusing something here. defer and reject are not part of the $q prototype. They're methods of $q itself, static methods. Deferreds and Promises aren't the same. They're two different types. In particular, Deferreds don't have the methods then, finally and catch.

As for instanceof, here is how it usually works:

var a = new Array();
console.log(a instanceof Array); // true

Array has the method Array.isArray. a is an instance of Array, but it doesn't have the method isArray. Its methods are from Array.prototype.

If we're creating something calling a constructor with the new keyword, we usually expect the created object to pass the check: createdObject instanceof usedConstructor. In particular, it works for ES6 Promises. From the fact that $q.resolve and the ability to use $q as a constructor were implemented, I deduce that $q is supposed to be compatible with ES6 promises. And making instanceof work is an additional step towards this compatibility.

@fa137
Copy link

fa137 commented Dec 17, 2015

Am I missing something?
I am assigning y with a new constructor, but it still isn't an instanceof of x.

http://plnkr.co/edit/wcRinNm59LUmYwRCZmr8?p=preview

@jbedard
Copy link
Contributor

jbedard commented Dec 17, 2015

I think this makes sense. Currently $Q is not a proper constructor, even though it attempts to be...

@thorn0
Copy link
Contributor Author

thorn0 commented Dec 17, 2015

@fa137 By using return in the constructor, you broke instanceof exactly the same way Angular did it with $q.

object instanceof constructor
The instanceof operator tests presence of constructor.prototype in object's prototype chain.

(from MDN)

@fa137
Copy link

fa137 commented Dec 17, 2015

@thorn0 Thanks for clearing it up! 👍

You are absolutely right then, we need a way to identify whether an object is a promise.

EDIT:
Did a small tweak to find out if it's a promise: http://plnkr.co/edit/j3A4RlWHS5c6SkiJinjR?p=preview

@thorn0
Copy link
Contributor Author

thorn0 commented Dec 17, 2015

@fa137 Your check doesn't really check if an object is a $q promise. It will as well pass for any promise implementation: jQuery, native ES2015, etc. Even when it comes just to Angular, we have two different kinds of promises here: $q and $$q. And what if we want to find out whether a promise in question is constructed with $q or with $$q?

@lgalfaso
Copy link
Contributor

@thorn0 you are right, and this seams like a reasonable request

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants