546

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?

10
  • 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. Commented Jan 2, 2015 at 17:56
  • 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. Commented Jan 2, 2015 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. Commented Jan 25, 2015 at 17:49
  • 4
    const isPromise = v => typeof v === 'object' && typeof v.then === 'function' Commented Jan 16, 2021 at 3:29
  • 1
    @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. Commented Sep 6, 2022 at 17:39

20 Answers 20

511

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

Sign up to request clarification or add additional context in comments.

6 Comments

How does executing Promise.resolve(x) (Q(x) in Q) inform you whether or not x is a promise?
@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.
@BenjaminGruenbaum But why Promise.resolve(a_promise) would give the a_promise?
Also, in the async context await thing makes it to resolve either to the things value or to its promised value.
@JoeFlack might be good to elaborate why/how it doesn't help in React cases, or perhaps post and link to a separate question.
|
335

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

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

})

21 Comments

@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.
This answer, though perhaps good advice, does not actually answer the question.
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.
@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.
@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.
|
122

Disclaimer: this is not a good answer to the updated question, 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.

9 Comments

should you use === instead of ==?
@NeilS == is fine.
This will also fail for promises that are not of the same realm.
"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
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.
|
118

Disclaimer: this is not a good answer to the updated question; works for native only, and not across realms. Follow the 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.

8 Comments

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.
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 thenables, not only other native promises. So should your code. So instanceof Promise is not a good solution.
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.
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 { <pending> } false. As you can see it's a promise alright - and yet the instanceof Promise test returns false?
This will fail for promises that are not of the same realm.
|
78
if (typeof thing?.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}

2 Comments

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.
if (p && 'then' in p && typeof p.then === 'function')
38

Detecting native and compatible Promises

To check if the given object is a Promise (native or custom that aims to be recognized as one), use:

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

Calling toString directly from Object.prototype returns a native string representation of the given object type, which is "[object Promise]" for spec-aligned Promise implementations (includes Angular's ZoneAwarePromise). This is based on Symbol.toStringTag, which is "Promise" per spec.* Combined with .then, this approach:

  • Bypasses false positives unrelated to Promise, such as:
    • A self-defined object type with the same constructor name ("Promise").
    • A self-written .toString method on the given object.
    • An object with a .then method that is not a Promise.
  • Works across multiple realms (e.g. iframes or windows) and also if the global Promise is intentionally monkey-patched.
    Using instanceof would fail:
    • in cross-realm scenarios
    • in scenarios where a given object (p) is a native Promise (e.g. created by the browser engine through async-await) while the Promise in instanceof Promise is a custom Promise implementation (e.g. provided by Zone.js/ZoneAwarePromise in Angular).

* Legacy libraries like Bluebird (which now recommends using native Promises) and Q (deprecated) diverge from the spec by returning "[object Object]".src The same applies to thenables like jQuery Deferred. For these, typeof p?.then === "function" is the only applicable approach, which may be sufficient depending on the project's needs.

Detecting strictly native Promises

To check if the object is a truly native Promise, we can leverage the fact that async functions always return a native Promise created by the engine (this is per spec and cannot be overridden). We use this to obtain the native Promise prototype via Object.getPrototypeOf for comparison:

function isNativePromise(p, NativePromiseProto = Object.getPrototypeOf((async () => {})())) {
  // NativePromiseProto is from the caller's realm by default.
  // Pass a native Promise prototype from the target realm for cross-realm checks.
  return Object.getPrototypeOf(p) === NativePromiseProto;
}

Unlike .constructor (which is a regular property on Promise.prototype that can be overwritten), Object.getPrototypeOf reads the internal [[Prototype]] slot directly.

Alternatively, for cross-realm scenarios and without creating a native Promise on each call, we can use Function.prototype.toString to compare against a known native function:

function looksLikeNativePromise(p) {
  return 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 the ECMAScript spec Function.prototype.toString, the string representation of a built-in function must follow the NativeFunction syntax:

function PropertyNameopt ( FormalParameters ) { [ native code ] }

where PropertyName must match the function's [[InitialName]] internal slot. We compare the constructor's string representation against a known native function (Function) with the name swapped to "Promise".

Note: I've named it looksLikeNativePromise since Function.prototype.toString itself can be monkey-patched. Zone.js from Angular goes to great lengths to make ZoneAwarePromise indistinguishable from native Promise (patching Function.prototype.toString, Symbol.toStringTag, the constructor name, etc.) but still gets detected as a custom implementation when using the above isNativePromise.

Server-side runtimes (Node.js, Deno, Bun, etc.)

util.types.isPromise() can reliably detect native Promises in server-side runtimes:

import util from "node:util";

util.types.isPromise(Promise.resolve(42)); // true
util.types.isPromise(someCustomPromise); // false for ZoneAwarePromise, Bluebird, etc.

2 Comments

"we can leverage the fact that async functions always return a native Promise created by the engine, which cannot be intercepted" - nothing prevents them from setting Promise.prototype.constructor = ZoneAwarePromise or similar
The sentence is still true. The Promise instance returned by async functions is always native and cannot be intercepted. But you're also right that the .constructor can be overwritten which was the weak link. I've replaced it the Object.getPrototypeOf approach which reads the internal [[Prototype]] slot directly. Of course, Object.getPrototypeOf itself could be overwritten too, but at that point we're in a fundamentally compromised environment where no client-side JS-level detection can be trusted.
32

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.

Update 2025:

Here is the up-to-date code:

export function isPromise(value: any): value is Promise<unknown> {
  return typeof value?.then === 'function';
}

1 Comment

It does it a bit differently in the meantime, but the idea is the same. Updated code is here now: github.com/graphql/graphql-js/blob/main/src/jsutils/…
16

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

Comments

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.

3 Comments

this works, according to here: "if the [awaited] value is not a promise, [the await expression] converts the value to a resolved Promise, and waits for it"
It is basically what has been suggested in the accepted answer except here async-await syntax is used instead of Promise.resolve()
Promise.resolve or the global Promise itself can be monkey-patched like in the Angular scenario. The Promise created through async-await is strictly native created by the engine. See also stackoverflow.com/a/45762727/5846045
8

Here is the code from 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 has a then method, it should be treat as a Promise.

2 Comments

why we need obj === 'function' condition btw?
Same as this answer, any object can have a method "then" and thus cannot be always treated as a promise.
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

Comments

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?

1 Comment

({ constructor: Promise })?
3

I use this function as a universal solution:

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

Comments

2

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'

7 Comments

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.
Agreed, but I don’t see why would anyone create sublasses of promises
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
@BenjaminGruenbaum The above example works in most cases, if you create your own subclass you should add the tests on its name
You can, but if you already know what objects there are you already know if stuff are promises or not.
|
1

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') { ... }

3 Comments

This seems to work in JavaScript as well - why mention TypeScript specifically ?
The other solutions all worked, except the TypeScript compiler complained about them, so I provided a solution that the TypeScript compiler was fine with - to save the next person some time.
Typescript explicitly includes an interface for this called PromiseLike although tbf to you it isn't well-documented.
0
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));
});

Comments

-2
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

1 Comment

Why is this better? Please explain your answer.
-2

Into 2025, and without obsolete hooks...

  • By checking the type of instance:
const isPromise = (value:any) => value instanceof Promise;
  • By checking for then function presence:
const isPromise = (value:any) => typeof value?.then === 'function';

Both work equally well today.

2 Comments

Both of these have already been suggested by earlier answers. Both come with caveats that need mentioning, and no, they do not "work equally well".
Also not sure what you refer to by "obsolete hooks"
-4

ES6:

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

console.log(promise.toString().includes('Promise')); //true

2 Comments

Any object that has (or has overwritten) toString method can just return a string that includes "Promise".
This answer is bad for many reasons, the most obvious being 'NotAPromise'.toString().includes('Promise') === true
-4

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.