Как мне узнать, является ли объект Обещанием?

Будь то 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
Другие вопросы по тегам