Это обещание ES6 или обещание синей птицы, обещание Q и т.д.
Как я могу проверить, является ли данный объект обещанием?
Это обещание ES6 или обещание синей птицы, обещание Q и т.д.
Как я могу проверить, является ли данный объект обещанием?
Если у него есть функция .then
- то, что используются только стандартные библиотеки обещаний.
В спецификации Promises/A + есть понятие, называемое then
, которое в основном является "объектом с методом then
". Promises будет и должен ассимилировать что-либо с помощью метода then. Все обещания, о которых вы говорили, делают это.
Если мы посмотрим на спецификацию:
2.3.3.3 если
then
- это функция, назовите ее с x как это, первый аргумент solvePromise и второй аргумент rejectPromise
Это также объясняет обоснование этого дизайнерского решения:
Эта обработка
then
ables позволяет взаимодействовать с обеими реализациями, если они выставляют метод Promises/A + -compliantthen
. Он также позволяет реализациям Promises/A + "ассимилировать" несоответствующие реализации с помощью разумных методов.
Не следует - вместо этого вызывать Promise.resolve(x)
(Q(x)
в Q), который всегда будет конвертировать любое значение или внешний then
в надежное обещание. Это безопаснее и проще, чем выполнять эти проверки самостоятельно.
Вы всегда можете запустить его через набор тестов: D
Проверка того, что что-то обещание излишне усложняет код, просто используйте Promise.resolve
Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {
})
Вот мой оригинальный ответ, который с тех пор был ратифицирован в спецификации как способ проверить обещание:
Promise.resolve(obj) == obj
Это работает, потому что алгоритм явно требует, чтобы Promise.resolve
должен возвращать точный объект, переданный в if и , только если это обещание по определению спецификации.
У меня есть еще один ответ, который говорил об этом, но я изменил его на что-то еще, когда он не работал с Safari в то время. Это было год назад, и теперь это работает надежно даже в Safari.
Я бы отредактировал свой первоначальный ответ, за исключением того, что это было неправильно, учитывая, что теперь больше людей проголосовали за измененное решение в этом ответе, чем оригинал. Я считаю, что это лучший ответ, и я надеюсь, что вы согласитесь.
Обновление: Это уже не лучший ответ. Пожалуйста, проголосуйте мой другой ответ.
obj instanceof Promise
должен это сделать. Обратите внимание, что это может работать только с родным es6 promises.
Если вы используете прокладку, библиотеку обещаний или что-то еще, притворяющееся перспективным, тогда может быть более целесообразным протестировать "thenable" (что-либо с методом .then
), как показано в другие ответы здесь.
if (typeof thing.then === 'function') {
// probably a promise
} else {
// definitely not a promise
}
Чтобы увидеть, является ли данный объект Обещанием ES6, мы можем использовать этот предикат:
function isPromise(p) {
return p && Object.prototype.toString.call(p) === "[object Promise]";
}
Call
toString
напрямую из Object.prototype
возвращает нативное строковое представление заданного типа объекта, которое в нашем случае является "[object Promise]"
. Это гарантирует, что данный объект
toString
метод toString
данного объекта.instanceof
или isPrototypeOf
. Однако любой конкретный хост-объект, тег которого изменен с помощью Symbol.toStringTag
, может вернуть "[object Promise]"
. Это может быть ожидаемый результат или нет в зависимости от проекта (например, если есть пользовательская реализация Promise).
Чтобы увидеть, является ли объект родным ES6 Promise, мы можем использовать:
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
}
Согласно этому и этому разделу спецификации, строковое представление функции должно быть:
"Идентификатор функции (FormalParameterList opt) {FunctionBody}"
который обрабатывается соответственно выше. FunctionBody - это [native code]
во всех основных браузерах.
MDN: Function.prototype.toString
Это работает в разных контекстах среды.
Вот форма кода https://github.com/ssnau/xkit/blob/master/util/is-promise.js
!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
если объект с методом then
, его следует рассматривать как Promise
.
Если вы используете TypScript, я хотел бы добавить, что вы можете использовать функцию "предикат типа". Просто следует обернуть логическую проверку в функции, которая возвращает x is Promise<any>
и вам не нужно будет делать приемы типа. Ниже в моем примере 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
Не ответ на полный вопрос, но я думаю, что стоит упомянуть, что в Node.js 10 добавлена новая функция util, называемая isPromise
которая проверяет, является ли объект родным обещанием или нет:
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()
}
Если функция возвращает обещание, она будет ожидать и возвращаться с разрешенным значением. Если функция возвращает значение, оно будет считаться разрешенным.
Если функция не возвращает обещание сегодня, но завтра возвращает одно или объявляется как асинхронное, вы будете ориентированы на будущее.
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));
});
Вот как пакет graphql-js обнаруживает обещания:
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
value
- это возвращаемое значение вашей функции. Я использую этот код в своем проекте, и пока у меня нет проблем.
после поиска надежного способа обнаружения функций Async или даже Promises, я закончил использование следующего теста:
() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
ES6:
const promise = new Promise(resolve => resolve('olá'));
console.log(promise.toString().includes('Promise')); //true