June 10th 2019
You're Missing the Point of Promises
Contents
사실, 프로미스는 callback의 집합과는 관련이 없고, 그렇게 단순하지 않습니다. 프로미스는 좀 더 복잡한 내용이 담겨져 있으며, 말하자면 동기함수와 비동기 함수가 연결될 수 있도록 하는 기능을 제공해 줍니다.
이게 무슨 의미일까요? 동기 함수에는 중요한 두 가지 측면이 존재합니다.
두 가지 모두 다 구성적인 측면과 관련이 있습니다. 우리는 어떠한 함수의 반환값을 다른 함수에 전달하고 이러한 작업을 계속해서 할 수 있습니다. 더 중요한 점은 이러한 절차에서 처리하지 못 하는 상황이 발생하면, composition chain에 있는 한 함수가 예외를 던질 수 있습니다. 그러면 이미 구성되어 있는 다른 단계들은 모두 건너뛰고, 에러를 처리할 수 있는 catch 구문으로 넘겨집니다.
그럼 비동기 세계를 살펴보겠습니다. 우리는 더이상 어떠한 값은 반환할 수 없습니다. 어떠한 결과값이 제때에 준비되지 않기 때문입니다. 유하하게, 예외를 던질수도 없습니다. 아무도 그 예외를 받아서 처리하지 않기 때문입니다. 그래서 우리는 중첩된 callback을 이용해 값을 반환하고 이를 이용하는 "callback hell"이라는 것에 맞닥뜨리게 됩니다. 그리고 이러한 상황에서 에러 처리는 직접 상위 chain으로 전달해 주는 작업을 해야합니다. 차라리 에러를 던지지 말던가 domains 같은 툴을 사용하는 것이 나을것 같습니다.
프로미스의 핵심은 비동기 세계에서 우리에게 비동기 작업을 처리할 함수들을 구성할 수 있게하고, 에러 버블링을 제공한다는 것입니다. 우리의 함수가 프로미스를 반환하면, 이 프로미스는 다음의 두 가지 중 한가지 작업을 하게됩니다.
우리가 프로미스에 이어지는 then 함수를 적절히 구성했다면, fulfillment, rejection은 마치 동기적인 코드와 같이 작동합니다. fulfillment는 compositional chain의 흐름에 따라 실행됩니다. 하지만, rejection에 의해 도중에 흐름이 끊긴 경우는 우리가 어떻게 처리할지 준비하지 않으면, 처리가 되지 않습니다.
아래의 코드를 한 번 살펴보겠습니다.
getTweetsFor('domenic') // promise-returning function
.then(function(tweets) {
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
return expandUrlUsingTwitterApi(mostRecentSHortUrl); // promise-returning function
})
.then(httpGet) // promise-returning function
.then(
function(responseBody) {
console.log('Most recent link text:', responseBody);
},
function(error) {
console.error('Error with the twitterverse:', error);
}
);
위 코드를 동기적인 내용의 코드로 보면 아래와 같습니다.
try {
var tweets = getTweetsFor('domenic'); // blocking
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
var responseBody = httpGet(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking
console.log('Most recent link text:', responseBody);
} catch (error) {
console.error('Error with the twitterverse: ', error);
}