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?
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
thenis 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+-compliantthenmethod. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.
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.
You can always run it through the test suite :D
Promise.resolve takes care of this automatically for you - you always get a promise.Promise.resolve(a_promise) would give the a_promise?async context await thing makes it to resolve either to the things value or to its promised value.Checking if something is promise unnecessarily complicates the code, just use Promise.resolve
Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) { }) 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.
=== instead of ==?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.
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.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?if (typeof thing?.then === 'function') { // probably a promise } else { // definitely not a promise } if (p && 'then' in p && typeof p.then === 'function')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
toString method of the given object.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.
({ [Symbol.toStringTag]: "Promise", constructor: Promise }) is a promise?Symbol.toStringTag was already addressed in the answer. Feel free to enhance the answer if needed.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'; } 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 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.
Promise.resolve()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.
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
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?
({ constructor: Promise })?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' Promise and create instances of that, this test can fail. this should work for most of what you're trying to test for though.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 promisesFor 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') { ... } PromiseLike although tbf to you it isn't well-documented.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)); }); 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
Into 2025, and without obsolete hooks...
const isPromise = (value:any) => value instanceof Promise; then function presence:const isPromise = (value:any) => typeof value?.then === 'function'; Both work equally well today.
ES6:
const promise = new Promise(resolve => resolve('olá')); console.log(promise.toString().includes('Promise')); //true toString method can just return a string that includes "Promise".'NotAPromise'.toString().includes('Promise') === trueuse 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
.thenmethod, 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.thenmethod, like a Promise..thenmethod that is not a Promise, does not behave like a Promise and had no intention of being used like a Promise. Checking for a.thenmethod just tells you that the if object doesn't have a.thenmethod, then you don't have a Promise. The inverse - that the existence of a.thenmethod means that you do have a Promise - is not necessarily true..thenmethod. 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.const isPromise = v => typeof v === 'object' && typeof v.then === 'function'.thenmethod, 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 thanthen.