Anti-promise Promise 역모드

출처: Promise Anti-patterns

Nested Promise(중첩된 Promise)

    loadSomething().then(function(something) {
        loadAnotherthing().then(function(anthor) {
            DoSomethingOnThem(something, anthor);
        })
    })

네가 이렇게 쓴 이유는 2개promise의 결과를 처리해야 하기 때문이다. then()는 지난promise가 되돌아온 결과를 수신했기 때문에 체인 쓰기를 통해 연결할 수 없다.
To Fix:
    q.all([loadSomething(), loadAnotherThing()])
        .spread(function(something, another) {
            DoSomethingOnThem(something, another);
        })
q.all() 방법은 loadSomethingloadAnotherThing 모두resolve에 의해 전송된 spread 방법의 리셋을 기다릴 것입니다.

The Broken Chain(끊어진 promise 체인)


먼저 코드 한 토막을 보십시오.
    function anAsyncCall() {
        var promise = doSomethingAsync();
        promise.then(function() {
            somethingComplicated();
        })
        
        return promise;
    }

이런 작법의 문제는 somethingComplicated 방법에서 오류를 던져 포획할 수 없다는 것이다.Promise는 체인식이어야 하며, 매번 then() 방법을 호출한 후에 새로운 promise 방법으로 되돌아온다.보편적인 묘사법은 마지막으로 catch() 방법을 호출하면 앞의 일련의 promise 작업에서 발생하는 모든 error 작업이 포착된다는 것이다.
위의 코드에서 당신이 마지막으로 되돌아온 것이 첫 번째 promise 가 아니라 이 promise 호출 then() 방법의 결과라면 promise 체인도 끊어진다.
To Fix:
    function anAsyncCall() {
        var promise = doSomethingAsync();
        return promise.then(function() {
            somethingComplicated()
        });   
}

The Collection Kerfuffle


수조가 있다면, 수조 안의 모든 항목은 비동기적으로 처리해야 한다.그래서 당신은 귀속을 통해 어떤 일을 할 수 있다.
     function workMyCollection(arr) {
        var resultArr = [];
        function _recursive(idx) {
            if (idx >= resultArr.length) return resultArr;
            
            return doSomethingAsync(arr[idx]).then(function(res) {
            resultArr.push(res);
            return _recursive(idx + 1);
        });
    }

    return _recursive(0);
}

이 코드는 첫눈에 좀 이해가 안 되는 것 같은데.문제는 mapreduce 방법이 있는지 모르면 몇 개의 항목이 연결되어야 하는지 알 수 없다는 것이다. 그러면 알이 아프다.
To Fix:
위에서 언급한 q.all 방법은 하나의 수조를 받아들인다. 이 수조 안은 모두 promise이다. 그리고 q.all 방법은 이 모든 것promise이 모두 resolve되기를 기다린 후에 하나의 수조를 얻어 이전promiseresolve 후의 값으로 구성된다.이때 우리는 map 방법을 통해 위의 코드를 개선할 수 있다.
    function workMyCollection(arr) {
        return q.all(arr.map(function(item) {
            return doSomethingAsync(item);
        }));
    }

위의 귀속문법은 직렬 처리되지만q.allmap를 통해 개작한 후 병행 처리되기 때문에 더욱 효율적이다.
만약 당신이 promise 직렬 처리를 필요로 한다면, reduce 방법을 사용할 수 있습니다.
    function workMyCollection(arr) {
        return arr.reduce(function(promise, item) {
            return promise.then(function(result) {
                return doSomethingAsyncWithResult(item, result);
            }, q());
        });
    }

비록 매우 깔끔하지는 않지만, 틀림없이 조리가 있을 것이다.

The Ghost Promise


어떤 방법은 때로는 비동기적으로 처리해야 하고, 때로는 필요하지 않을 수도 있다.이때도 두 가지 다른 처리 방식의 일관성을 확보하기 위해 promise를 만들 수 있다.
    var promise ;
    if(asyncCallNeeded) {
        promise = doSomethingAsync();
    } else {
        promise = Q.resolve(42);
    }
    
    promise.then(function() {
        doSomethingCool();
    });

더 깔끔한 묘사법은 Q() 방법으로 하나 또는promise을 감싸는 것이다.
    Q(asyncCallNeeded ? doSomethingAsync() : 42)
        .then(function(value) {
            dosomethingGood();
        })
        .catch(function(err) {
            handleTheError();
        });

The Overly Keen Error Handler

then() 방법은 2개의 매개 변수를 수신하고 fullfilled handlerrejected handler:
    somethingAync.then(function() {
        return somethingElseAsync();
    }, function(err) {
        handleMyError(err);
    })

그러나 이런 작법의 문제점 중 하나는 오류가 somethingElseAsync 방법에서 나오면 이 오류는 error handler 포획될 수 없다는 것이다.
이때 error handler 단독으로 then() 방법에 등록해야 한다.
To Fix:
    somethingAsync
        .then(function() {
            return somethingElseAsync()
        })
        .then(null, function(err) {
            handleMyError(err);
        });

또는 catch() 방법을 사용합니다.
    somethingAsync()
        .then(function() {
            return somethingElseAsync();
        })
        .catch(function(err) {
            handleMyError(err);
        });

이 두 가지 기법은 모두 promise 체인 처리 과정에서 오류가 발생하면 포획될 수 있도록 하기 위해서다.

The Forgotten Promise


너는 방법을 호출하여 하나 promise 를 되돌렸다.그러나 당신은 이것promise을 잊어버리고 자신만의 것을 만들었습니다.
    var deferred = Q.defer();
    doSomethingAsync().then(function(res) {
        res = manipulateMeInSomeWay(res);
        deferred.resolve(res);
    }, function(err) {
        deferred.reject(err);
    });
    
    return deferred.promise(;

이 안에는 쓸모없는 코드가 많이 존재하고 Promise의 간결한 사상과 서로 어긋난다.
To Fix:
    return doSomethingAsync().then(function(res) {
        return manipulateMeInSomeWay(res);
    });

관련 자료:
  • Q
  • 좋은 웹페이지 즐겨찾기