Как узнать, возвращает ли функция Promise? [Дубликат]

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
205
задан Benjamin Gruenbaum 2 January 2015 в 21:55
поделиться

13 ответов

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

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

В спецификации Promises / A + есть понятие, называемое then, которое в основном является «объектом с методом then». Обещания будут и должны ассимилировать все с помощью метода 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

200
ответ дан Benjamin Gruenbaum 17 August 2018 в 22:38
поделиться
  • 1
    Отличный ответ. Одно замечание: «Не следует - вместо этого называть Promise.resolve (x)» это не всегда вариант. Если вы действительно хотите проверить , является ли объект «обещанием» (возможно then ), Promise.resolve ничего не скажет вам и преобразует объекты в процесс , Таким образом, на самом деле ответ будет (с учетом объекта с именем subject): var isPromise = typeof subject.then == 'function'; – Stijn de Witt 15 March 2016 в 23:18
  • 2
    -1. Все обещания имеют метод then, но все методы then не принадлежат к Promise. Поэтому ваше заявление недействительно, поэтому не отвечайте на вопрос. – Oleander 24 August 2016 в 17:24
  • 3
    @Oleander это буквально, как это определено в спецификации ECMAScript и спецификации Promises / A +. Если он имеет метод then, то он будет рассматриваться как обещание и должен быть рекурсивно ассимилирован с помощью Promise.prototype.then, Promise.resolve all race или параметра fulfill конструктора обещаний. Таким образом, вы можете технически проверить по-другому, но сам язык проверяет часто, и он проверяет это. Я не уверен, что означает ваш downvote или что не так, потому что раздел, который вы комментируете, начинается с «Как решает библиотека обещаний». и это правильно – Benjamin Gruenbaum 24 August 2016 в 19:49
  • 4
    @BenjaminGruenbaum В моем первом комментарии, возможно, было немного грубо, сожалею об этом. Я просто хотел сохранить его коротким и формальным. Второе утверждение гласит: How do I test to see if a given object is a Promise?. То есть; если у вас есть какой-либо объект, то каким образом это происходит, если это Promise или нет. Проверка существования then подскажет вам, что объект является либо Promise, либо Object методом then, поэтому не отвечает на данный вопрос. Это увеличивает вероятность того, что объект является Promise, но это все. – Oleander 24 August 2016 в 20:07
  • 5
    @DonHatch спецификация A + относится к «обещанию». как "что-то из текущей реализации" и "thenable" как «что-то, что следует рассматривать как обещание». Внимательно прочитайте. – Benjamin Gruenbaum 27 October 2016 в 06:09

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

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

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

  • обходит ложные срабатывания, такие как ..: Тип самоопределенного объекта с тем же именем конструктора («Promise»). Самонаписанный метод toString данного объекта.
  • Работает в нескольких контекстах среды (например, iframes) в отличие от instanceof или isPrototypeOf.
8
ответ дан Boghyon Hoffmann 17 August 2018 в 22:38
поделиться
  • 1
    Для чего это стоит - мы сопротивлялись этому в bluebird, чтобы люди все еще могли его протестировать, но мы можем Symbol.toStringTag довольно легко переопределить это в ES2015. См. Object.prototype.toString.call({ get [Symbol.toStringTag]() { return 'Promise' }}); – Benjamin Gruenbaum 3 July 2018 в 13:17

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

obj instanceof Promise

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

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

34
ответ дан Community 17 August 2018 в 22:38
поделиться
  • 1
    С тех пор, как указал мне , что Promise.resolve(obj) == obj не работает в Safari. Вместо этого используйте instanceof Promise. – jib 25 September 2015 в 19:45
  • 2
    Это не работает надежно и заставило меня безумно сложно отслеживать проблему. Скажем, у вас есть библиотека, в которой используется es6.promise shim, и вы используете Bluebird где-то, у вас будут проблемы. Эта проблема возникла у меня в Chrome Canary. – vaughan 6 February 2016 в 05:35
  • 3
    Да, этот ответ на самом деле ошибочен. Я оказался здесь для такой сложной проблемы. Вы действительно должны проверить obj && typeof obj.then == 'function' вместо этого, потому что он будет работать со всеми типами обещаний и на самом деле является способом, рекомендованным спецификацией и используемым реализациями / полиполками. Нативный Promise.all, например, будет работать на всех then ables, а не только на других нативных обещаниях. Так и ваш код. Таким образом, instanceof Promise не является хорошим решением. – Stijn de Witt 16 March 2016 в 00:14
  • 4
    Последующие действия - это хуже: на node.js 6.2.2, используя только собственные обещания, я сейчас пытаюсь отладить проблему, когда console.log(typeof p, p, p instanceof Promise); производит этот вывод: object Promise { <pending> } false. Как вы видите, это обещание в порядке - и тем не менее тест instanceof Promise возвращает false? – Mörre 22 June 2016 в 15:42
  • 5
    Это не даст обещаний, которые не относятся к одной и той же сфере. – Benjamin Gruenbaum 24 August 2016 в 19:54

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

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

})
99
ответ дан Esailija 17 August 2018 в 22:38
поделиться
  • 1
    так что Promise.resolve может обрабатывать что-нибудь , которое появляется на его пути? Наверняка ничего, но я думаю, что-нибудь разумное? – Alexander Mills 9 January 2016 в 23:50
  • 2
    @AlexMills да, это даже работает для нестандартных обещаний, таких как jQuery. Он может выйти из строя, если у объекта есть метод then, который имеет совершенно другой интерфейс от обещания. – Esailija 10 January 2016 в 09:35
  • 3
    Этот ответ, хотя, возможно, хороший совет, на самом деле не отвечает на вопрос. – Stijn de Witt 16 March 2016 в 00:16
  • 4
    Если вопрос действительно не о том, кто действительно реализует библиотеку обещаний, вопрос недействителен. Нужно только проверить библиотеку обещаний, после чего вы всегда можете использовать свой метод .resolve, как я показал. – Esailija 16 March 2016 в 10:23
  • 5
    @Esalija Вопрос представляется мне важным и важным, а не только разработчиком библиотеки обещаний. Это также актуально для пользователя библиотеки обещаний, которая хочет знать, как будут / должны / должны выполняться реализации и как разные библиотеки обещаний будут взаимодействовать друг с другом. В частности, этот пользователь очень встревожен очевидным фактом, что я могу сделать обещание X для любого X, кроме случаев, когда X является «обещанием». (что-нибудь «обещание» означает здесь - вот в чем вопрос), и я определенно заинтересован в том, чтобы точно знать, где границы этого исключения лежат. – Don Hatch 21 October 2016 в 13:08

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

Promise.resolve(obj) == obj

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

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

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

56
ответ дан jib 17 August 2018 в 22:38
поделиться
  • 1
    следует ли использовать === вместо ==? – Neil S 3 August 2016 в 19:29
  • 2
    Это также не даст обещаний, которые не относятся к одной и той же сфере. – Benjamin Gruenbaum 24 August 2016 в 19:54
  • 3
    «обещание по определению спецификации» представляется «средним» обещанием, созданным тем же конструктором, что и обещание, созданное через Promise.resolve (), «будет» - поэтому это не сможет определить, например. полифулированное обещание на самом деле является обещанием – VoxPelli 25 November 2016 в 16:12
  • 4
    Этот ответ можно было бы улучшить, если бы он начинался с того, что он рассказывал, как вы интерпретируете вопрос, а не начинаете с ответа сразу - OP, к сожалению, не сделал его совершенно ясным, и у вас его нет, поэтому на этом этапе ОП, писатель и читатель, вероятно, находятся на трех разных страницах. Документ, к которому вы обращаетесь, гласит: «если аргумент является обещанием , созданным этим конструктором », то выделенная часть имеет решающее значение. Хорошо бы сказать, что это вопрос, на который вы отвечаете. Также, что ваш ответ полезен для пользователя этой библиотеки, но не для разработчика. – Don Hatch 15 December 2016 в 00:21
  • 5
    Не используйте этот метод, вот почему, больше для точки Бенджамина Грюенбаума. gist.github.com/reggi/a1da4d0ea4f1320fa15405fb86358cff – ThomasReggi 7 March 2018 в 06:04

Не ответ на полный вопрос, но я думаю, что стоит упомянуть, что в Node.js 10 была добавлена ​​новая функция использования, названная isPromise , которая проверяет, является ли объект родным обещанием или не:

const utilTypes = require('util').types
const b_Promise = require('bluebird')

utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false
1
ответ дан LEQADA 17 August 2018 в 22:38
поделиться

ES6:

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

console.log(promise.toString().includes('Promise')); //true
-3
ответ дан Mathias Gheno Azzolini 17 August 2018 в 22:38
поделиться
  • 1
    Любой объект, который имеет (или перезаписал) метод toString, может просто вернуть строку, которая включает "Promise". – Boghyon Hoffmann 12 January 2018 в 00:11
  • 2
    Этот ответ плох по многим причинам, наиболее очевидным является 'NotAPromise'.toString().includes('Promise') === true – damd 23 January 2018 в 00:05
if (typeof thing.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
30
ответ дан mchandleraz 17 August 2018 в 22:38
поделиться
  • 1
    что, если вещь не определена? вам нужно защититься от этого через предмет & amp; & amp; ... – mrBorna 2 December 2017 в 15:33
  • 2
    & Quot; вероятно, & Quot; это не лучший способ точно сказать, является ли thing обещанием или нет, поскольку любая вещь может иметь метод с именем then .. – Boghyon Hoffmann 27 March 2018 в 14:36
  • 3
    не лучший, но, безусловно, очень вероятно; зависит также от объема проблемы. Написание защиты на 100% обычно применяется в открытых открытых API-интерфейсах или где вы знаете, что форма / подпись данных полностью открыта. – rob2d 1 May 2018 в 05:10

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

2
ответ дан Murilo Perrone 17 August 2018 в 22:38
поделиться
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));
});
1
ответ дан purplecabbage 17 August 2018 в 22:38
поделиться

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

() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
0
ответ дан Sebastien H. 17 August 2018 в 22:38
поделиться
  • 1
    если вы подклассом Promise и создаете экземпляры этого, этот тест может завершиться неудачно. это должно работать для большей части того, что вы пытаетесь проверить, хотя. – theram 31 May 2018 в 17:17
  • 2
    Согласен, но я не понимаю, почему кто-нибудь создавал подвалы обещаний – Sebastien H. 3 June 2018 в 11:10
  • 3
    fn.constructor.name === 'AsyncFunction' неверно - это означает, что что-то является функцией асинхронного вызова, а не обещанием - также не гарантируется работа, потому что люди могут подклассы обещать – Benjamin Gruenbaum 3 July 2018 в 13:15
  • 4
    @BenjaminGruenbaum Приведенный выше пример работает в большинстве случаев, если вы создаете свой собственный подкласс, вы должны добавить тесты на его имя – Sebastien H. 3 July 2018 в 14:37
  • 5
    Вы можете, но если вы уже знаете, какие объекты есть, вы уже знаете, являются ли вещи обещаниями или нет. – Benjamin Gruenbaum 3 July 2018 в 16:15

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

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

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

6
ответ дан ssnau 17 August 2018 в 22:38
поделиться
  • 1
    почему нам нужно obj === 'function' condition btw? – Alendorff 25 April 2017 в 15:14
  • 2
    То же, что и этот ответ , любой объект может иметь способ "then" и поэтому не всегда можно рассматривать как обещание. – Boghyon Hoffmann 27 March 2018 в 14:42

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

async myMethod(promiseOrNot){
  const theValue = await promiseOrNot
}
0
ответ дан Steven Spungin 17 August 2018 в 22:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: