Как мне узнать, является ли объект Обещанием?
Будь то ES6 Promise или Bluebird Promise, Q Promise и т. Д.
Как мне проверить, является ли данный объект Обещанием?
20 ответов
Как решает библиотека обещаний
Если у него есть .then
Функция - это единственное стандартное использование библиотек обещаний.
В спецификации Promises/A+ есть понятие под названием then
в состоянии, которое в основном "объект с then
method". Обещания будут и должны ассимилировать что-либо с помощью метода then. Все реализации обещаний, которые вы упомянули, делают это.
Если мы посмотрим на спецификации:
2.3.3.3 если
then
является функцией, вызовите ее с x как этот, первый аргумент resolPromise, а второй аргумент rejectPromise
Это также объясняет обоснование этого проектного решения:
Это лечение
then
Возможность позволяет взаимодействовать реализациям обещаний, если они предоставляют Promises/A+-совместимыйthen
метод. Это также позволяет реализациям Promises/A+ "ассимилировать" несовместимые реализации разумными методами then.
Как вы должны решить
Вы не должны - вместо этого позвоните Promise.resolve(x)
(Q(x)
в Q), который всегда будет конвертировать любое значение или внешний then
в состоянии в надежное обещание. Это безопаснее и проще, чем выполнять эти проверки самостоятельно.
действительно нужно быть уверенным?
Вы всегда можете запустить его через набор тестов:D
Проверка того, что что-то обещает излишне усложняет код, просто используйте Promise.resolve
Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {
})
Вот мой оригинальный ответ, который с тех пор был утвержден в спецификации как способ проверки на обещание:
Promise.resolve(obj) == obj
Это работает, потому что алгоритм явно требует Promise.resolve
должен возвращать точный переданный объект, если и только если это обещание по определению спецификации.
У меня здесь есть другой ответ, который раньше говорил это, но я изменил его на что-то другое, когда он не работал с Safari в то время. Это было год назад, и теперь это надежно работает даже в Safari.
Я бы отредактировал свой первоначальный ответ, за исключением того, что он был ошибочным, учитывая, что к настоящему моменту за измененное решение в этом ответе проголосовало больше людей, чем оригинала. Я считаю, что это лучший ответ, и я надеюсь, что вы согласны.
Обновление: это больше не лучший ответ. Пожалуйста, проголосуйте за мой другой ответ.
obj instanceof Promise
должен сделать это. Обратите внимание, что это может надежно работать только с собственными обещаниями es6.
Если вы используете прокладку, библиотеку обещаний или что-то еще, притворяющееся подобным обещанию, тогда может быть более уместно проверить "жизнеспособность" (что-либо с .then
метод), как показано в других ответах здесь.
if (typeof thing.then === 'function') {
// probably a promise
} else {
// definitely not a promise
}
Чтобы увидеть, является ли данный объект собственным обещанием ES6, мы можем использовать этот предикат:
function isPromise(value) {
return value && Object.prototype.toString.call(value) === "[object Promise]";
}
Call
ИНГ toString
прямо из Object.prototype
возвращает нативное строковое представление заданного типа объекта, которое "[object Promise]"
в нашем случае. Это гарантирует, что данный объект
- Обход ложных срабатываний, таких как..:
- Самоопределенный тип объекта с тем же именем конструктора ("Обещание").
- Само написанный
toString
метод данного объекта.
- Работает в разных контекстах среды (например, в фреймах) в отличие от
instanceof
или жеisPrototypeOf
,
Вот как пакет graphql-js обнаруживает обещания:
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
value
Возвращаемое значение вашей функции. Я использую этот код в своем проекте, и у меня пока нет проблем.
Не ответ на полный вопрос, но я думаю, что стоит упомянуть, что в Node.js 10 новая утилита под названием isPromise
был добавлен, который проверяет, является ли объект родным Promise или нет:
const utilTypes = require('util').types
const b_Promise = require('bluebird')
utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false
Если вы используете асинхронный метод, вы можете сделать это и избежать двусмысленности
async myMethod(promiseOrNot){
const theValue = await promiseOrNot
}
Вот кодовая форма https://github.com/ssnau/xkit/blob/master/util/is-promise.js
!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
если объект с then
метод, это следует рассматривать как Promise
,
Если вы используете Typescript, я хотел бы добавить, что вы можете использовать функцию "предиката типа". Просто следует завернуть логическую проверку в функцию, которая возвращает x is Promise<any>
и вам не нужно будет делать Typecast. Ниже на моем примере c
это либо обещание, либо один из моих типов, который я хочу преобразовать в обещание, вызвав c.fetch()
метод.
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;
}
Дополнительная информация: https://www.typescriptlang.org/docs/handbook/advanced-types.html
Все, что подталкивает к возможной синхронизации
Возможно, можно сделать подобное;
var isPromise = x => Object(x).constructor === Promise;
Я проверил это на некоторых крайних случаях, которые я могу придумать, и, похоже, он работает.
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
Я не проверял это ни с какими библиотеками, не являющимися родными, но какой теперь смысл?
После поиска надежного способа обнаружения асинхронных функций или даже обещаний, я использовал следующий тест:
() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
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));
});
Я использую эту функцию как универсальное решение:
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'
)
}
Как по мне - эта проверка лучше, попробуйте
Для тех, кто пытается сделать это в Typescript – какие ошибки с другими предоставленными решениями:
if (p instanceof Object && 'then' in p && typeof p.then === 'function') { ... }
In Angular:
import { isPromise } from '@angular/compiler/src/util';
if (isPromise(variable)) {
// do something
}
J
использовать эту библиотеку
https://www.npmjs.com/package/is-обещание
import isPromise from 'is-promise';
isPromise(Promise.resolve());//=>true
isPromise({then:function () {...}});//=>true
isPromise(null);//=>false
isPromise({});//=>false
isPromise({then: true})//=>false
ES6:
const promise = new Promise(resolve => resolve('olá'));
console.log(promise.toString().includes('Promise')); //true