Как определить, является ли объект обещанием?

Это обещание ES6 или обещание синей птицы, обещание Q и т.д.

Как я могу проверить, является ли данный объект обещанием?

Ответ 1

Как библиотека обещаний решает

Если у него есть функция .then - то, что используются только стандартные библиотеки обещаний.

В спецификации Promises/A + есть понятие, называемое then, которое в основном является "объектом с методом then". Promises будет и должен ассимилировать что-либо с помощью метода then. Все обещания, о которых вы говорили, делают это.

Если мы посмотрим на спецификацию:

2.3.3.3 если then - это функция, назовите ее с x как это, первый аргумент solvePromise и второй аргумент rejectPromise

Это также объясняет обоснование этого дизайнерского решения:

Эта обработка then ables позволяет взаимодействовать с обеими реализациями, если они выставляют метод Promises/A + -compliant then. Он также позволяет реализациям Promises/A + "ассимилировать" несоответствующие реализации с помощью разумных методов.

Как вы должны решить

Не следует - вместо этого вызывать Promise.resolve(x) (Q(x) в Q), который всегда будет конвертировать любое значение или внешний then в надежное обещание. Это безопаснее и проще, чем выполнять эти проверки самостоятельно.

действительно нужно быть уверенным?

Вы всегда можете запустить его через набор тестов: D

Ответ 2

Проверка того, что что-то обещание излишне усложняет код, просто используйте Promise.resolve

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

})

Ответ 3

Вот мой оригинальный ответ, который с тех пор был ратифицирован в спецификации как способ проверить обещание:

Promise.resolve(obj) == obj

Это работает, потому что алгоритм явно требует, чтобы Promise.resolve должен возвращать точный объект, переданный в if и , только если это обещание по определению спецификации.

У меня есть еще один ответ, который говорил об этом, но я изменил его на что-то еще, когда он не работал с Safari в то время. Это было год назад, и теперь это работает надежно даже в Safari.

Я бы отредактировал свой первоначальный ответ, за исключением того, что это было неправильно, учитывая, что теперь больше людей проголосовали за измененное решение в этом ответе, чем оригинал. Я считаю, что это лучший ответ, и я надеюсь, что вы согласитесь.

Ответ 4

Обновление: Это уже не лучший ответ. Пожалуйста, проголосуйте мой другой ответ.

obj instanceof Promise

должен это сделать. Обратите внимание, что это может работать только с родным es6 promises.

Если вы используете прокладку, библиотеку обещаний или что-то еще, притворяющееся перспективным, тогда может быть более целесообразным протестировать "thenable" (что-либо с методом .then), как показано в другие ответы здесь.

Ответ 5

if (typeof thing.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}

Ответ 6

Чтобы увидеть, является ли данный объект Обещанием ES6, мы можем использовать этот предикат:

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

Call toString напрямую из Object.prototype возвращает нативное строковое представление заданного типа объекта, которое в нашем случае является "[object Promise]". Это гарантирует, что данный объект

  • Обход ложных срабатываний, таких как..:
    • Определенный пользователем тип объекта с тем же именем конструктора ("Обещание").
    • toString метод toString данного объекта.
  • Работает в нескольких контекстах среды (например, в iframes) в отличие от 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

Это работает в разных контекстах среды.

Ответ 7

Вот форма кода https://github.com/ssnau/xkit/blob/master/util/is-promise.js

!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';

если объект с методом then, его следует рассматривать как Promise.

Ответ 8

Если вы используете 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

Ответ 9

Не ответ на полный вопрос, но я думаю, что стоит упомянуть, что в 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

Ответ 10

Если вы используете асинхронный метод, вы можете сделать это и избежать двусмысленности.

async myMethod(promiseOrNot){
  const theValue = await promiseOrNot()
}

Если функция возвращает обещание, она будет ожидать и возвращаться с разрешенным значением. Если функция возвращает значение, оно будет считаться разрешенным.

Если функция не возвращает обещание сегодня, но завтра возвращает одно или объявляется как асинхронное, вы будете ориентированы на будущее.

Ответ 11

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));
});

Ответ 12

Вот как пакет graphql-js обнаруживает обещания:

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

value - это возвращаемое значение вашей функции. Я использую этот код в своем проекте, и пока у меня нет проблем.

Ответ 13

после поиска надежного способа обнаружения функций Async или даже Promises, я закончил использование следующего теста:

() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'

Ответ 14

ES6:

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

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