개체가 약속인지 어떻게 알 수 있습니까?


336

ES6 Promise이든 블루 버드 Promise, Q Promise 등

주어진 개체가 약속인지 확인하려면 어떻게합니까?


3
기껏해야 .then방법을 확인할 수는 있지만 가지고있는 것이 확실하다는 약속은 없습니다. 그 시점에서 아는 것은 약속 과 같은.then 방법 을 노출시키는 무언가가 있다는 것입니다 .
Scott Offen

@Scott 약속 사양을 명시 적으로 구별하지 마십시오.
Benjamin Gruenbaum

6
내 요점은 누구나 .then약속이 아닌 방법 을 드러내고 약속처럼 행동하지 않으며 약속처럼 사용할 의도가없는 객체를 만들 수 있다는 것 입니다. A에 대한 확인 .then방법 그냥 객체가있는 경우 있음을 알려줍니다 하지 않는.then방법을, 당신이 하지 않는 약속이있다. .then방법 의 존재 가 당신 약속을 가지고 있음을 의미한다는 반대 는 반드시 사실이 아닙니다.
Scott Offen

3
@ScottOffen 정의에 따르면, 약속을 식별하는 유일한 방법은 약속이 있는지 확인하는 것 .then입니다. 네, 오탐 (false positive)의 가능성을 가지고 있지만 모든 약속 라이브러리 (그 때문에 그들은 모두에 의존한다는 가정입니다 에 의존). 내가 볼 수있는 한 유일한 대안은 Benjamin Gruenbaum의 제안을 받아 약속 테스트 스위트를 통해 실행하는 것입니다. 그러나 실제 프로덕션 코드에는 실용적이지 않습니다.
JLRishe

답변:


342

약속 라이브러리가 결정하는 방법

.then함수 가 있다면 그것은 유일한 표준 약속 라이브러리 사용입니다.

Promises / A + 사양에는 then기본적으로 " then메소드가 있는 객체" 인 able 이라는 개념 이 있습니다. 약속은 그때의 방법으로 무엇이든 받아 들일 것 입니다. 언급 한 모든 약속 구현 이이 작업을 수행합니다.

우리가 사양 을 보면 :

2.3.3.3 then함수 인 경우 x를 다음과 같이 호출하고 첫 번째 인수 resolvePromise, 두 번째 인수 rejectPromise를 호출하십시오.

또한이 설계 결정의 근거를 설명합니다.

이러한 능력의 처리는 then약속 / A + 호환 then방법 을 노출하는 한 약속 구현이 상호 운용되도록합니다 . 또한 Promises / A + 구현은 부적합한 구현을 합리적인 방법으로 "어셈블리"할 수 있습니다.

어떻게 결정해야합니까

당신은 안 - 대신 전화 Promise.resolve(x)( Q(x)것 Q에) 항상 값 또는 외부 변환 then신뢰할 수있는 약속으로 할 수 있습니다. 이러한 점검을 직접 수행하는 것보다 안전하고 쉽습니다.

정말로 확실해야합니까?

항상 테스트 스위트를 통해 실행할 수 있습니다 . : D


168

무언가 약속이 불필요하게 코드를 복잡하게 만드는지 확인하십시오. Promise.resolve

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

})

1
그래서 Promise.resolve 가 오는 모든 것을 처리 할 수 있습니까? 확실히 아무것도 아니지만 합리적인 것 같아요?
Alexander Mills

3
@AlexMills 예, jQuery promise와 같은 비표준 약속에도 작동합니다. 객체에 promise와 완전히 다른 인터페이스를 가진 then 메소드가 있으면 실패 할 수 있습니다.
Esailija

19
이 답변은 아마도 좋은 조언이지만 실제로 질문에 대답하지는 않습니다.
Stijn de Witt

4
실제로 약속 라이브러리를 구현하는 사람에 대한 질문이 아니라면 질문은 유효하지 않습니다. 약속 라이브러리 만 검사를 수행하면됩니다. 그 후에는 항상 보여준 것처럼 .resolve 메소드를 사용할 수 있습니다.
Esailija

4
@Esalija 질문은 약속 라이브러리의 구현 자뿐만 아니라 관련성이 있고 중요한 것으로 보입니다. 또한 구현이 어떻게 동작해야하는지, 어떻게 행동해야하는지, 서로 다른 약속 라이브러리가 어떻게 상호 작용하는지 알고 싶어하는 약속 라이브러리 사용자 와 도 관련이 있습니다 . 특히,이 사용자는 X가 "약속"(여기서 "약속"이 의미하는 것이 무엇이든 문제가되는 경우)을 제외하고는 모든 X에 대해 X를 약속 할 수 있다는 명백한 사실에 크게 놀랐습니다. 그 예외의 경계가 어디에 있는지 정확히 아는 것.
돈 해치

104

다음 은 약속을 테스트하는 방법으로 사양에서 비준 된 원래의 대답입니다 .

Promise.resolve(obj) == obj

이것은 알고리즘 이 스펙의 정의에 의해 약속 된 경우에만Promise.resolve 전달 된 정확한 객체를 반환하도록 요구 하기 때문에 작동 합니다 .

여기에 다른 대답이 있습니다.이 말은 Safari에서 작동하지 않을 때 다른 것으로 변경했습니다. 1 년 전이었으며 이제 Safari에서도 안정적으로 작동합니다.

나는 지금보다 더 많은 사람들이 그 대답에서 변경된 해결책에 투표 한 것을 감안할 때, 잘못된 생각을 제외하고는 나의 원래의 대답을 편집했을 것입니다. 이것이 더 나은 답변이라고 생각하며 동의합니다.


10
===대신에 사용해야 ==합니까?
Neil S

12
이것은 같은 영역이 아닌 약속에도 실패합니다.
Benjamin Gruenbaum

4
"사양의 정의에 의한 약속"은 "Promise.resolve ()를 통해 생성 된 약속과 동일한 생성자에 의해 생성 된 약속"을 의미하는 것으로 보입니다. 따라서 예를 들어 감지하지 못할 것입니다. polyfilled 약속은 실제로 약속입니다
VoxPelli

3
이 답변은 답변을 시작하는 대신 질문을 해석하는 방법을 명시하여 시작하면 개선 될 수 있습니다. OP는 불행히도 전혀 명확하게하지 않았으며 아직은 그렇지 않았습니다. OP, 작가 및 독자는 3 개의 다른 페이지에있을 수 있습니다. 당신이 언급 한 문서는 " 논리 가이 생성자에 의해 생성 된 약속이라면 "이탤릭체 부분이 결정적 이라고 말합니다 . 그것이 당신이 대답하고있는 질문이라고 진술하는 것이 좋을 것입니다. 또한 귀하의 답변은이 라이브러리의 사용자에게는 유용하지만 구현자는 아닙니다.
Don Hatch

1
이 방법을 사용하지 마십시오. @BenjaminGruenbaum의 요점에 더 많은 이유가 있습니다. gist.github.com/reggi/a1da4d0ea4f1320fa15405fb86358cff
ThomasReggi

61

업데이트 : 이것은 더 이상 최선의 대답이 아닙니다. 대신 다른 답변을 투표하십시오 .

obj instanceof Promise

해야합니다. 이는 기본 es6 약속에서만 안정적으로 작동 할 수 있습니다.

shim, promise 라이브러리 또는 promise와 비슷한 척하는 것을 사용하는 경우 .then여기에있는 다른 답변에서 볼 수 있듯이 "thenable"( 방법이있는 항목) 을 테스트하는 것이 더 적절할 수 있습니다 .


그것은 이후 한 나에게 지적되어Promise.resolve(obj) == objSafari에서 늘 일을. instanceof Promise대신 사용하십시오 .
jib

2
이것은 안정적으로 작동하지 않으며 문제를 추적하기가 엄청나게 어렵습니다. es6.promise shim을 사용하는 라이브러리가 있고 Bluebird를 사용하면 문제가 있다고 가정합니다. 이 문제는 Chrome Canary에서 나타났습니다.
vaughan

1
예,이 답변은 실제로 잘못되었습니다. 나는 정확하게 추적하기 어려운 문제로 여기에 왔습니다. 당신은 정말 확인해야 obj && typeof obj.then == 'function'그 약속의 모든 종류의 작업을 실제로 구현 / polyfills에 의해 사양 추천 및 사용 방법입니다 있기 때문에, 대신. Promise.all예를 들어 기본 은 then다른 기본 약속뿐만 아니라 모든 능력에 적용 됩니다. 코드도 마찬가지입니다. 따라서 instanceof Promise좋은 해결책이 아닙니다.
Stijn de Witt

2
후속-그것은 더 나쁘다 : 네이티브 약속 만 사용하는 node.js 6.2.2에서는 지금 console.log(typeof p, p, p instanceof Promise);이 출력을 생성 하는 문제를 디버깅하려고합니다 object Promise { <pending> } false. 보시다시피 그것은 약속입니다. 그러나 instanceof Promise테스트는 반환 false됩니까?
Mörre

2
동일한 영역이 아닌 약속에는 실패합니다.
Benjamin Gruenbaum

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

6
일이 정의되지 않으면 어떻게 되나요? 당신은 그것을 통해 & & ...을 통해 경계해야합니다
mrBorna

최고는 아니지만 확실히 가능성이 높습니다. 또한 문제의 범위에 따라 다릅니다. 방어 적으로 100 %를 작성하는 것은 일반적으로 개방형 공개 API 또는 데이터의 형태 / 시그니처가 완전히 개방형임을 알고있는 경우에 적용됩니다.
rob2d

17

주어진 객체가 ES6 Promise인지 확인하기 위해이 술어를 사용할 수 있습니다.

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

CalltoString에서 직접을 보내면 주어진 객체 유형의 기본 문자열 표현Object.prototype반환 됩니다. 이것은 주어진 객체가"[object Promise]"

  • 다음과 같은 오 탐지를 무시합니다.
    • 생성자 이름이 동일한 자체 정의 개체 유형 ( "Promise")
    • toString주어진 객체의 자체 작성 방법.
  • 또는 과 달리instanceof 여러 환경 컨텍스트 (예 : iframe) 에서 작동 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

이것은 여러 환경 컨텍스트에서도 작동합니다.


12

전체 질문에 대한 대답은 아니지만 Node.js 10에서 isPromise객체가 기본 약속인지 여부를 확인 하는 새로운 util 함수 가 추가 되었다는 것을 언급 할 가치가 있다고 생각합니다 .

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

utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false

11

이것은 graphql-js 패키지가 약속을 감지 하는 방법입니다 .

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

value함수의 반환 값입니다. 내 프로젝트 에서이 코드를 사용하고 있으며 지금까지 아무런 문제가 없습니다.


6

다음은 코드 형식입니다 https://github.com/ssnau/xkit/blob/master/util/is-promise.js

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

then메소드 가있는 오브젝트 인 경우 로 취급해야합니다 Promise.


3
왜 우리는 obj === 'function'condition btw가 필요합니까?
Alendorff

이 답변 과 마찬가지로 모든 객체에는 "then"메소드가 있으므로 항상 약속으로 취급 할 수 없습니다.
Boghyon Hoffmann

6

당신이 사용하는 경우 타이프 라이터를 , 난 당신이 "유형 술어"기능을 사용할 수있는 추가하고 싶습니다. 논리 검증을 리턴하는 함수로 랩핑하면 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


6

비동기 방식이라면이 작업을 수행하고 모호성을 피할 수 있습니다.

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

함수가 promise를 반환하면 확인 된 값으로 기다렸다가 반환됩니다. 함수가 값을 반환하면 해결 된 것으로 간주됩니다.

함수가 오늘 약속을 반환하지 않지만 내일이 약속을 반환하거나 비동기로 선언되면 미래를 보장 할 수 있습니다.


이 작품에 따라 여기 "에서 [기다려온] 값이 약속하지 않은 경우, [await를 표현]는 해결 약속에 값을 변환하고, 그것을 기다립니다"
pqnet

기본적으로 async-await 구문이 사용되는 것을 제외하고는 허용 된 답변에서 제안 된 것입니다.Promise.resolve()
B12Toaster

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

2

이 기능을 범용 솔루션으로 사용합니다.

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

-1

비동기 함수 또는 약속 을 감지 하는 신뢰할 수있는 방법을 찾은 후에 다음 테스트를 사용했습니다.

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

해당 Promise인스턴스 를 서브 클래 싱 하고 생성하면이 테스트가 실패 할 수 있습니다. 이것은 테스트하려고하는 대부분의 경우 작동합니다.
theram

동의하지만, 왜 누군가 약속의 소문을 만들지 모르겠습니다.
Sebastien H.

fn.constructor.name === 'AsyncFunction'잘못되었습니다-무언가가 비동기 함수이며 약속이 아님을 의미합니다. 또한 사람들이 약속을 서브 클래스 할 수 있기 때문에 작동하지 않을 수도 있습니다.
Benjamin Gruenbaum

@BenjaminGruenbaum 위의 예제는 대부분의 경우 작동합니다. 자신 만의 서브 클래스를 만드는 경우 이름에 테스트를 추가해야합니다
Sebastien H.

당신은 할 수 있지만, 이미 어떤 물체가 있는지 알고 있다면 물건이 약속인지 아닌지를 이미 알고 있습니다.
벤자민 Gruenbaum

-3

ES6 :

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

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

2
메소드를 가지고 있거나 덮어 쓴 모든 객체는 toString포함하는 문자열을 반환 할 수 있습니다 "Promise".
Boghyon Hoffmann

4
이 대답은 여러 가지 이유로 나쁜, 가장 눈에 띄는 존재'NotAPromise'.toString().includes('Promise') === true
DAMD
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.