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
?
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 then
able 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
then
ables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliantthen
method. 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 then
able 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. –
Churchill Promise.resolve(a_promise)
would give the a_promise
? –
Impostor async
context await thing
makes it to resolve either to the thing
s value or to its promised value. –
Impostor Checking if something is promise unnecessarily complicates the code, just use Promise.resolve
Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {
})
typeof thing.then == 'function'
. –
Drawknife await res;
actually does the job in both JS and TS. Voilà. –
Impostor 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? –
Tonry Promise.resolve( value )
–
Insurrectionary 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.
===
instead of ==
? –
Autosuggestion ==
is fine. –
Verlaverlee BLUEBIRD
? –
Wheeling 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.
Promise.resolve(obj) == obj
wont work in Safari. Use instanceof Promise
instead. –
Verlaverlee 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. –
Cyrillus 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
? –
Eidetic Promise.resolve(obj) == obj
, appears to since have been solidified in the spec and now finally works in Safari as well, so perhaps I should change it back? –
Verlaverlee if (typeof thing?.then === 'function') {
// probably a promise
} else {
// definitely not a promise
}
?
in thing?.then
handles the undefined check. This is called "optional chaining". Read more: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… –
Sindhi if (p && 'then' in p && typeof p.then === 'function')
–
Fulminous 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]";
}
Call
ing 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.
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.
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()
–
Mullock 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
.
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?
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. –
Cuticle 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 –
Churchill .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. –
Consummate 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. –
Churchill 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));
});
I use this function as a universal solution:
function isPromise(value) {
return value && value.then && typeof value.then === 'function';
}
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
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') { ... }
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"
. –
Wohlert 'NotAPromise'.toString().includes('Promise') === true
–
Toomer 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
© 2022 - 2024 — McMap. All rights reserved.
.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. – Coucher.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. – Coucher.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. – Ruddock... instanceof Promise
work? – Broncoconst isPromise = v => typeof v === 'object' && typeof v.then === 'function'
– Galesinstanceof 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. – Tonry.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 thanthen
. – Tonry