명시 적 약속 생성 반 패턴이란 무엇이며 어떻게 피합니까?

May 22 2014

다음과 같은 코드를 작성했습니다.

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

누군가는 이것을 각각 " 지연된 안티 패턴 "또는 " Promise생성자 안티 패턴 "이라고합니다.이 코드에 대해 나쁜 점은 무엇이며 왜 안티 패턴 이라고 부르 나요?

답변

380 BenjaminGruenbaum May 22 2014 at 17:07

연기 안티 패턴 (현재 명시 적 건설 안티 패턴) 에 의해 만들어 낸 Esailija은 내가 먼저 약속을 사용할 때 약속하기에 새로운 일반적인 안티 패턴 사람들입니다, 내가 직접했습니다. 위 코드의 문제점은 체인을 약속한다는 사실을 활용하지 못한다는 것입니다.

Promise는 .then연결될 수 있으며 Promise를 직접 반환 할 수 있습니다. 의 코드는 getStuffDone다음과 같이 다시 작성할 수 있습니다.

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

약속은 비동기 코드를 더 읽기 쉽게 만들고 그 사실을 숨기지 않고 동기 코드처럼 작동하는 것입니다. Promise는 일회성 작업의 값에 대한 추상화를 나타내며 프로그래밍 언어로 된 명령문 또는 표현의 개념을 추상화합니다.

API를 promise로 변환하고 자동으로 수행 할 수없는 경우 또는 이러한 방식으로 더 쉽게 표현되는 집계 함수를 작성할 때만 지연된 객체를 사용해야합니다 .

Esailija 인용 :

이것은 가장 일반적인 안티 패턴입니다. 약속을 실제로 이해하지 못하고이를 영광스러운 이벤트 이미 터 또는 콜백 유틸리티로 생각할 때이 문제에 빠지기 쉽습니다. 요약하자면 약속은 비동기 코드가 플랫 들여 쓰기 및 하나의 예외 채널과 같은 동기 코드의 손실 된 속성 대부분을 유지하도록 만드는 것입니다.

142 Bergi Aug 29 2014 at 20:28

뭐가 잘못 됐나요?

그러나 패턴은 작동합니다!

행운아. 안타깝게도 엣지 케이스를 잊었을 가능성이 있으므로 그렇지 않을 것입니다. 내가 본 사건의 절반 이상에서 저자는 오류 처리기를 처리하는 것을 잊었습니다.

return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
        resolve(result.property.example);
    });
})

다른 promise가 거부되면 새 promise (처리 될 위치)로 전파되는 대신 눈에 띄지 않게 발생하며 새 promise는 영원히 보류되어 누출을 유발할 수 있습니다.

콜백 코드가 오류를 발생시키는 경우에도 동일한 일이 발생합니다. 예를 들어가 result없고 property예외가 발생하는 경우입니다. 그것은 처리되지 않고 새로운 약속이 해결되지 않은 채로 남을 것입니다.

반대로 using .then()은 이러한 두 시나리오를 자동으로 처리하고 오류가 발생하면 새로운 promise를 거부합니다.

 return getOtherPromise().then(function(result) {
     return result.property.example;
 })

지연된 안티 패턴은 번거롭고 오류가 발생하기 쉽습니다 . .then()연결에 사용 하는 것이 훨씬 안전합니다.

그러나 나는 모든 것을 처리했습니다!

정말? 좋은. 그러나 이것은 특히 취소 또는 메시지 전달과 같은 다른 기능을 지원하는 promise 라이브러리를 사용하는 경우 매우 상세하고 풍부합니다. 아니면 미래에 그렇게 될까요? 아니면 라이브러리를 더 나은 라이브러리로 바꾸고 싶습니까? 이를 위해 코드를 다시 작성하고 싶지 않을 것입니다.

라이브러리의 메서드 ( then)는 기본적으로 모든 기능을 지원할뿐만 아니라 특정 최적화가있을 수도 있습니다. 그것들을 사용하면 코드가 더 빨라지거나 적어도 라이브러리의 향후 개정판에 의해 최적화 될 수 있습니다.

어떻게 피합니까?

따라서 수동으로 생성 Promise하거나 Deferred이미 존재하는 promise가 관련되어 있을 때마다 먼저 라이브러리 API를 확인하십시오 . 이연 안티 패턴은 종종 약속을 볼 사람들에 의해 적용된다 [전용] 관찰자 패턴으로 -하지만 약속이되어 콜백 이상 : 그들이 해야하는 작성 가능합니다. 모든 괜찮은 라이브러리에는 모든 생각할 수있는 방식으로 약속을 구성 할 수있는 사용하기 쉬운 기능이 많이 있으며 다루고 싶지 않은 모든 저수준 항목을 처리합니다.

기존 도우미 함수에서 지원하지 않는 새로운 방식으로 몇 가지 promise를 구성해야하는 경우 불가피한 Deferreds로 자신의 함수를 작성하는 것이 마지막 옵션이어야합니다. 보다 기능적인 라이브러리로 전환하거나 현재 라이브러리에 버그를 신고하는 것을 고려하십시오. 관리자는 기존 함수에서 구성을 도출하고, 새로운 도우미 함수를 구현하고, 처리해야하는 엣지 케이스를 식별하는 데 도움을 줄 수 있어야합니다.