498

Whether it's an ES6 Promise or a Bluebird Promise, Q Promise, etc.

How do I test to see if a given object is a Promise?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
theram
  • 5,503
  • 2
  • 13
  • 14
  • 4
    At best you could check for a `.then` method, but that wouldn't tell you that what you have is a Promise definitively. All you would know at that point is that you have something that exposes a `.then` method, *like* a Promise. – Scott Offen Jan 02 '15 at 17:56
  • @ScottOffen the promise specification _explicitly_ does not make a distinction. – Benjamin Gruenbaum Jan 02 '15 at 17:57
  • 8
    My point is that anyone can create an object that exposes a `.then` method that is not a Promise, does not behave like a Promise and had no intention of being used like a Promise. Checking for a `.then` method just tells you that the if object *doesn't* have a `.then` method, then you *don't* have a Promise. The inverse - that the existence of a `.then` method means that you *do* have a Promise - is not necessarily true. – Scott Offen Jan 02 '15 at 18:06
  • 5
    @ScottOffen By definition, the _only_ established way to identify a promise is to check whether it has a `.then` method. Yes, that has the potential for false positives, but it is the assumption that all promise libraries rely on (because that's all they _can_ rely on). The only alternative as far as I can see is to take Benjamin Gruenbaum's suggestion and run it through the promise test suite. But that's not practical for actual production code. – JLRishe Jan 25 '15 at 17:49
  • why doesn't `... instanceof Promise` work? – J-Cake Nov 06 '20 at 09:54
  • 3
    `const isPromise = v => typeof v === 'object' && typeof v.then === 'function'` – Dominic Jan 16 '21 at 03:29
  • @J-Cake because `instanceof Promise` would check if it is just one implementation of promises, and the whole ecosystem deliberately doesn't care which implementation you use - your check wouldn't be aligned with the rest of the language and tooling. Fine if you control and know the whole stack of JavaScript in your program but when using or implementing a library it can cause a bunch of false negatives which - if you're using them to choose different code paths - could break code and prevent interoperability. – mtraceur Sep 06 '22 at 16:39
  • @ScottOffen the problem with that point is that ever since JS standardized promises how they did, "Promise" is mostly just an implementation detail and the big picture relevant concept is "thenable", and (thanks to how JavaScript is insanely loose with function parameters) as soon as someone gives something a `.then` method, they've *made it a thenable* - it might be a broken thenable, but it's a thenable, and everyone else's job is to treat it like a thenable and for them to either make it work like one or rename the method to something other than `then`. – mtraceur Sep 06 '22 at 17:39

19 Answers19

484

How a promise library decides

If it has a .then function - that's the only standard promise libraries use.

The Promises/A+ specification has a notion called thenable which is basically "an object with a then method". Promises will and should assimilate anything with a then method. All of the promise implementation you've mentioned do this.

If we look at the specification:

2.3.3.3 if then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise

It also explains the rationale for this design decision:

This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.

How you should decide

You shouldn't - instead call Promise.resolve(x) (Q(x) in Q) that will always convert any value or external thenable into a trusted promise. It is safer and easier than performing these checks yourself.

really need to be sure?

You can always run it through the test suite :D

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 4
    How does executing Promise.resolve(x) (Q(x) in Q) inform you whether or not x is a promise? – Ben Jan 23 '21 at 05:47
  • 3
    @Ben it doesn't, you almost never want to care about whether or not something is a promise - `Promise.resolve` takes care of this automatically for you - you always get a promise. – Benjamin Gruenbaum Jan 23 '21 at 17:58
  • @BenjaminGruenbaum But why `Promise.resolve(a_promise)` would give the `a_promise`? – Onkeltem Apr 01 '22 at 00:00
  • 2
    Also, in the `async` context `await thing` makes it to resolve either to the `thing`s value or to its *promised* value. – Onkeltem Apr 01 '22 at 00:17
  • @JoeFlack might be good to elaborate why/how it doesn't help in React cases, or perhaps post and link to a separate question. – mtraceur Sep 06 '22 at 16:42
  • @mtraceur so sorry, accidentally deleted my comment. I said doesn't help in react. I was lazy. I didn't try his response and now i want to. Maybe ill see if it works. More importantly, this answer doesn't answer OPs question. Doesn't respect individual use /edge cases. It should say at least that you can't check, or that it's hard to. Not just write it off and go on about design rationale. Otherwise the answer is fine. – Joe Flack Sep 09 '22 at 05:03
301

Checking if something is promise unnecessarily complicates the code, just use Promise.resolve

Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {

})
Esailija
  • 138,174
  • 23
  • 272
  • 326
  • 1
    so Promise.resolve can handle *anything* that comes its way? Surely not anything, but I guess anything reasonable? – Alexander Mills Jan 09 '16 at 22:50
  • 3
    @AlexMills yes, it even works for non standard promises like jQuery promise. It can fail if the object has a then method that has completely different interface from promise then. – Esailija Jan 10 '16 at 08:35
  • @Esailija Promise.resolve works for me in most cases, but for some metaprogramming I actually need to know the type - for example in your Bluebird library if a promise is not returned for certain scenarios a warning gets logged, so how do you tell in your lib whether or not a promise is returned? ;0 – Alexander Mills Feb 11 '16 at 07:38
  • @AlexMills there is no such warning, you can return anythhing from the function – Esailija Feb 12 '16 at 16:27
  • huh I was using sequelize and they use bluebird promises, and they claim the warning is from your lib :) older version? – Alexander Mills Feb 12 '16 at 18:50
  • The warning is when you dont return *anything*. Even return null works to silence the warning – Esailija Feb 12 '16 at 18:56
  • 73
    This answer, though perhaps good advice, does not actually answer the question. – Stijn de Witt Mar 15 '16 at 23:16
  • 6
    Unless the question is really about someone actually implementing a promise library, the question is invalid. Only a promise library would need to do the check, after that you can always use its .resolve method like I showed. – Esailija Mar 16 '16 at 09:23
  • 10
    @Esalija The question appears to me to be relevant and important, not just to an implementer of a promise library. It is also relevant to a *user* of a promise library who wants to know how implementations will/should/might behave and how different promise libraries will interact with each other. In particular, this user is greatly dismayed by the apparent fact that I can make a promise of an X for any X except when X is "promise" (whatever "promise" means here-- that's the question), and I am definitely interested in knowing exactly where the boundaries of that exception lie. – Don Hatch Oct 21 '16 at 13:08
  • @Esailija also, you seem to be assuming the OP wants to guarantee the thing *is* a promise. Seems to me, if OP is interested as a user of the library and not as implementor (we're all having to guess here, since OP hasn't provided context), it's more likely the opposite: that is, ey are probably interested in making sure eir object *isn't* going to be wrongly treated like a promise, i.e. that it *is* going to be correctly treated as a plain value. That's certainly a valid question, and I believe the answer to that is: check whether `typeof thing.then == 'function'`. – Don Hatch Oct 27 '16 at 15:36
  • @Esailija Promise libraries aren't the only thing that need to check if something is a promise. For instance, libraries such as mongoose need to do the check. I'm in the process of writing a database/library agnostic model autoloader interface for express, and i need to check that certain user setable functions such as establishConnection and createModel return a promise. – r3wt Dec 03 '16 at 12:55
  • 3
    @Esailija I have a variable that indicates whether the code is loaded or not. This variable could be a promise indicating it is loading which I should wait or a value indicating it is loaded so I can render it right way. Worth mention that I will render a loading animation which is very complicated if it is still loading. Hence, I cannot just wait anyways because if I always wait, the render() will be called with the code not loaded every time and create whole loading animation even if it is already ready. – SCLeo Jun 11 '17 at 15:58
  • Can I triple-upvote this? Should be the accepted answer. Thank you for the insight! – KateYoak Sep 04 '19 at 02:15
  • It doesn't answer the question but it's the neatest solution to the cause of this question – mkg Jul 18 '20 at 15:58
  • Don't use this, this approach will Swallow the exception in the callback – nolan Sep 25 '20 at 12:53
  • 1
    We often have parameter in our code, which can be anything. Checking if it's a Promise makes lots of sense in these cases. – Robo Robok Nov 12 '20 at 21:45
  • 1
    Though this is not a direct answer to the question, I liked it best. Because my real task was to DETECT the presence of a Promise and then use the result. And since I'm in TypeScript, I should have written a type-guard for this. BUT mere `await res;` actually does the job in both JS and TS. Voilà. – Onkeltem Dec 28 '21 at 13:45
  • @r3wt why do either Mongoose or your thing need to check anything? If you support promises then just blindly `await` (or `Promise.resolve`) everything at the spot where you'd need Promises resolved, and that'll Just Work whether it's a promise or not. Only if thenables are invalid bad inputs where it would be surprising to the user to have them not be awaited, then you might prefer to fail fast by detecting thenables and erroring out. Or if you want to give users strict "this will not `await` if you put in something that does not need awaiting" guarantees. Are those your use-cases? – mtraceur Sep 06 '22 at 16:50
  • @r3wt actually, in both of those valid reasons for checking I gave, it is still more appropriate to just check if it fulfills the thenable interface, because that's what would align with the expectations of programmers who actually take the time to get fully correct expectations by learning the spec. – mtraceur Sep 06 '22 at 17:32
  • @mtraceur No, you're right. I did end up just using `Promise.resolve( value )` – r3wt Sep 07 '22 at 14:48
  • Downvoted because I'd like to show a temporary "Loading ..." component precisely if the value is a promise. – O. R. Mapper May 04 '23 at 06:50
120

Disclaimer: not a good answer to updated OP, is per-library, and won't work across realms. Check for .then instead.

This answer, based on the spec is a way to test for a promise that works only sometimes, FYI.

Promise.resolve(obj) == obj &&
BLUEBIRD.resolve(obj) == obj

When this works it's because the algorithm explicitly demands that Promise.resolve must return the exact object passed in if and only if it is a promise created by this constructor.

jib
  • 40,579
  • 17
  • 100
  • 158
  • 18
    should you use `===` instead of `==`? – Neil S Aug 03 '16 at 19:29
  • 1
    @NeilS `==` [is fine](http://stackoverflow.com/questions/11403088/is-the-third-necessary-when-comparing-object-types/11403119). – jib Aug 03 '16 at 19:47
  • 16
    This will also fail for promises that are not of the same realm. – Benjamin Gruenbaum Aug 24 '16 at 19:54
  • 5
    "a promise by the definition of the spec" seems to be mean "a promise created by the same constructor as a promise created through Promise.resolve() would be" – so this will fail to detect if eg. a polyfilled Promise is actually a Promise – VoxPelli Nov 25 '16 at 15:12
  • @VoxPelli Correct. See accepted answer for the question "How do I tell if an object is a thenable?" – jib Nov 25 '16 at 16:01
  • 5
    This answer could be improved if it would start out by stating how you are interpreting the question rather than starting with an answer right away-- the OP has unfortunately not made it at all clear, and you haven't either, so at this point the OP, the writer, and the reader are likely on 3 different pages. The doc you refer to says "if the argument is a promise *produced by this constructor*", the italicized part being crucial. It would be good to state that that's the question you're answering. Also that your answer is useful for a user of this library but not the implementor. – Don Hatch Dec 14 '16 at 23:21
  • 1
    Don't use this method, here's why, more to @BenjaminGruenbaum's point. https://gist.github.com/reggi/a1da4d0ea4f1320fa15405fb86358cff – ThomasReggi Mar 07 '18 at 05:04
  • @DonHatch multiple tabs are open indeed, this answer has sent me on a wild goose chase, while accurate it is poorly delivered by OP. This answer is tad ambiguous for my taste and it can definitely can be improved upon. An edit would of been far more appropriate opposed to choosing to create a new answer and the said answer being of this quality. – User_coder Mar 22 '21 at 19:05
  • What is `BLUEBIRD`? – user31782 Nov 08 '22 at 09:38
115

Disclaimer: not a good answer to updated OP, works for native only, and not across realms. Follow accepted answer instead.

obj instanceof Promise

should do it. Note that this may only work reliably with native es6 promises.

If you're using a shim, a promise library or anything else pretending to be promise-like, then it may be more appropriate to test for a "thenable" (anything with a .then method), as shown in other answers here.

jib
  • 40,579
  • 17
  • 100
  • 158
  • It has since [been pointed out to me](http://stackoverflow.com/a/31621857/918910) that `Promise.resolve(obj) == obj` wont work in Safari. Use `instanceof Promise` instead. – jib Sep 25 '15 at 19:45
  • 4
    This doesn't work reliably and caused me an insanely hard to track problem. Say you have a library that uses the es6.promise shim, and you use Bluebird somewhere, you will have problems. This issue came up for me in Chrome Canary. – vaughan Feb 06 '16 at 04:35
  • 2
    Yes, this answer is actually wrong. I ended up here for exactly such a hard to track problem. You really should check `obj && typeof obj.then == 'function'` instead, because it will work with all types of promises and is actually the way recommended by the spec and used by the implementations / polyfills. Native `Promise.all` for example will work on all `then`ables, not only other native promises. So should your code. So `instanceof Promise` is not a good solution. – Stijn de Witt Mar 15 '16 at 23:14
  • 2
    It's the question that's wrong, not the answer. The right question is "How do I tell if an object is *thenable*? With duck-typing, one should inherently not care what type an object is. – jib Mar 16 '16 at 00:26
  • 2
    Followup - it's worse: On node.js 6.2.2 using only native promises I'm right now trying to debug a problem where `console.log(typeof p, p, p instanceof Promise);` produces this output: `object Promise { } false`. As you can see it's a promise alright - and yet the `instanceof Promise` test returns `false`? – Mörre Jun 22 '16 at 15:42
  • 1
    @MörreNoseshine Well, the original version of my answer, `Promise.resolve(obj) == obj`, appears to since have been [solidified in the spec](http://www.ecma-international.org/ecma-262/6.0/#sec-promise.resolve) and now finally works in Safari as well, so perhaps I should change it back? – jib Jun 23 '16 at 05:30
  • 2
    This will fail for promises that are not of the same realm. – Benjamin Gruenbaum Aug 24 '16 at 19:54
  • @jib well if it's part of the spec now then it might be worth mentioning, but for people trying to write really backwards-compatible code it might be worth also mentioning that it wasn't standardized until {time} and fixed in Safari until {version}. – mtraceur Sep 06 '22 at 17:03
72
if (typeof thing?.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
unobf
  • 7,158
  • 1
  • 23
  • 36
  • 9
    what if thing is undefined? you need to guard against that via thing && ... – mrBorna Dec 02 '17 at 14:33
  • 2
    not best but is definitely very likely; depends also on the scope of the problem. Writing 100% defensively is usually applicable in open ended public APIs or where you know the shape/signature of data is completely open-ended. – rob2d May 01 '18 at 05:10
  • 4
    @mrBorna The `?` in `thing?.then` handles the undefined check. This is called "optional chaining". Read more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining – Ajay Gupta Jan 15 '21 at 11:03
  • `if (p && 'then' in p && typeof p.then === 'function')` – Jonathan Oct 05 '21 at 08:24
  • 2
    The answer actually answers the question rather than deflecting away to other guidance. Thanks! – derpedy-doo May 01 '22 at 15:06
35

To see if the given object is a ES6 Promise, we can make use of this predicate:

function isPromise(p) {
  return p && Object.prototype.toString.call(p) === "[object Promise]";
}

Calling toString directly from the Object.prototype returns a native string representation of the given object type which is "[object Promise]" in our case. This ensures that the given object

  • Bypasses false positives such as..:
    • Self-defined object type with the same constructor name ("Promise").
    • Self-written toString method of the given object.
  • Works across multiple environment contexts (e.g. iframes) in contrast to instanceof or isPrototypeOf.

However, any particular host object, that has its tag modified via Symbol.toStringTag, can return "[object Promise]". This may be the intended result or not depending on the project (e.g. if there is a custom Promise implementation).


To see if the object is from a native ES6 Promise, we can use:

function isNativePromise(p) {
  return p && typeof p.constructor === "function"
    && Function.prototype.toString.call(p.constructor).replace(/\(.*\)/, "()")
    === Function.prototype.toString.call(/*native object*/Function)
      .replace("Function", "Promise") // replacing Identifier
      .replace(/\(.*\)/, "()"); // removing possible FormalParameterList 
}

According to this and this section of the spec, the string representation of function should be:

"function Identifier ( FormalParameterListopt ) { FunctionBody }"

which is handled accordingly above. The FunctionBody is [native code] in all major browsers.

MDN: Function.prototype.toString

This works across multiple environment contexts as well.

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
25

This is how graphql-js package detects promises:

function isPromise(value) {
  return Boolean(value && typeof value.then === 'function');
}

value is the returned value of your function. I'm using this code in my project and have no problem so far.

muratgozel
  • 2,333
  • 27
  • 31
15

Not an answer to the full question but I think it's worth to mention that in Node.js 10 a new util function called isPromise was added which checks if an object is a native Promise or not:

const utilTypes = require('util').types
const b_Promise = require('bluebird')

utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false
LEQADA
  • 1,913
  • 3
  • 22
  • 41
10

If you are in an async method you can do this and avoid any ambiguity.

async myMethod(promiseOrNot){
  const theValue = await promiseOrNot()
}

If the function returns promise, it will await and return with the resolved value. If the function returns a value, it will be treated as resolved.

If the function does not return a promise today, but tomorrow returns one or is declared async, you will be future-proof.

Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
  • 1
    this works, according to [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await): "if the [awaited] value is not a promise, [the await expression] converts the value to a resolved Promise, and waits for it" – pqnet Apr 11 '19 at 11:29
  • 1
    It is basically what has been suggested in the accepted answer except here async-await syntax is used instead of `Promise.resolve()` – Felix K. Mar 15 '20 at 12:57
8

Here is the code form https://github.com/ssnau/xkit/blob/master/util/is-promise.js

!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';

if an object with a then method, it should be treat as a Promise.

ssnau
  • 367
  • 2
  • 4
6

In case you are using Typescript, I'd like to add that you can use the "type predicate" feature. Just should wrap the logical verification in a function that returns x is Promise<any> and you won't need to do typecasts. Below on my example, c is either a promise or one of my types which I want to convert into a promise by calling the c.fetch() method.

export function toPromise(c: Container<any> | Promise<any>): Promise<any> {
    if (c == null) return Promise.resolve();
    return isContainer(c) ? c.fetch() : c;
}

export function isContainer(val: Container<any> | Promise<any>): val is Container<any> {
    return val && (<Container<any>>val).fetch !== undefined;
}

export function isPromise(val: Container<any> | Promise<any>): val is Promise<any> {
    return val && (<Promise<any>>val).then !== undefined;
}

More info: https://www.typescriptlang.org/docs/handbook/advanced-types.html

Murilo Perrone
  • 452
  • 4
  • 7
4

after searching for a reliable way to detect Async functions or even Promises, i ended up using the following test :

() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
Sebastien H.
  • 6,818
  • 2
  • 28
  • 36
  • if you subclass `Promise` and create instances of that, this test can fail. this should work for most of what you're trying to test for though. – theram May 31 '18 at 17:17
  • Agreed, but I don’t see why would anyone create sublasses of promises – Sebastien H. Jun 03 '18 at 11:10
  • `fn.constructor.name === 'AsyncFunction'` is wrong - it means something is an async function and not a promise - also it is not guaranteed to work because people can subclass promises – Benjamin Gruenbaum Jul 03 '18 at 13:15
  • @BenjaminGruenbaum The above example works in most cases, if you create your own subclass you should add the tests on its name – Sebastien H. Jul 03 '18 at 14:37
  • You can, but if you already know what objects there are you already know if stuff are promises or not. – Benjamin Gruenbaum Jul 03 '18 at 16:15
  • @Benjamin Gruenbaum Well... if for some reason you subclass the Promise constructor (which i think, is not a very good idea) then it is technically no more a Promise right? I believe subclassing Promises are not that wise since the subclass can not access the `.then()` as the Promise constructor do not have `.then()` or `.catch()` or `.finally()` under it's prototype. The subclass has to implement them explicitly for it's instances, if need be. I think. – Redu Mar 01 '21 at 17:52
  • @Redu it's technically a promise - but in every place the language is interacting with promises it will fail. That is: if you `await` it or `return` it from a promise chain `then` or async function - it will still call the `then` you overrode. In retrospect (knowing and talking to the people involved with speccing promises as well as being a tiny bit involved myself) - promise subclassing would not have been a thing. – Benjamin Gruenbaum Mar 02 '21 at 07:24
4

Anything that pushes a possibly synch value into Promise.resolve(value) for the comfort of avoiding comparison turns your code into an otherwise avoidable async. Sometimes you don't want it at that stage. You want to know the result evaluated right before some earlier resolution in the microtask queue bites you right..?

One can possibly do like;

var isPromise = x => Object(x).constructor === Promise;

I checked it against some edge cases that i can think of and it seems to work.

isPromise(undefined);                                           // <- false
isPromise(null);                                                // <- false
isPromise(0);                                                   // <- false
isPromise("");                                                  // <- false
isPromise({});                                                  // <- false
isPromise(setTimeout);                                          // <- false
isPromise(Promise);                                             // <- false
isPromise(new Promise((v,x) => setTimeout(v,1000,"whatever"))); // <- true
isPromise(fetch('http://example.com/movies.json'));             // <- true

I haven't checked it up against any non-native librarires but what's the point now?

Redu
  • 25,060
  • 6
  • 56
  • 76
2
it('should return a promise', function() {
    var result = testedFunctionThatReturnsPromise();
    expect(result).toBeDefined();
    // 3 slightly different ways of verifying a promise
    expect(typeof result.then).toBe('function');
    expect(result instanceof Promise).toBe(true);
    expect(result).toBe(Promise.resolve(result));
});
purplecabbage
  • 495
  • 3
  • 8
2

I use this function as a universal solution:

function isPromise(value) {
  return value && value.then && typeof value.then === 'function';
}
safrazik
  • 1,517
  • 10
  • 14
0
const isPromise = (value) => {
  return !!(
    value &&
    value.then &&
    typeof value.then === 'function' &&
    value?.constructor?.name === 'Promise'
  )
}

As for me - this check is better, try it out

0

For those trying to do this in Typescript - which errors with the other provided solutions:

if (p instanceof Object && 'then' in p && typeof p.then === 'function') { ... }
TrevTheDev
  • 2,616
  • 2
  • 18
  • 36
-2

use this library

https://www.npmjs.com/package/is-promise

import isPromise from 'is-promise';
 
isPromise(Promise.resolve());//=>true
isPromise({then:function () {...}});//=>true
isPromise(null);//=>false
isPromise({});//=>false
isPromise({then: true})//=>false
Acid Coder
  • 2,047
  • 15
  • 21
-3

ES6:

const promise = new Promise(resolve => resolve('olá'));

console.log(promise.toString().includes('Promise')); //true
  • 2
    Any object that has (or has overwritten) `toString` method can just return a string that includes `"Promise"`. – Boghyon Hoffmann Jan 11 '18 at 23:11
  • 6
    This answer is bad for many reasons, the most obvious being `'NotAPromise'.toString().includes('Promise') === true` – damd Jan 22 '18 at 23:05