Promise 이전엔 콜백(callback) 지옥이란 것이 존재했어요.
최초 함수 호출 시 콜백 함수를 함께 전달하고
전달된 콜백 함수 안에서 함수 호출 시 다른 콜백 함수를 전달하고,
마찬가지로 그 다른 콜백 함수 안에서 함수 호출 시에도 또 다른 콜백 함수를 전달하고
...
코드로는 대충 이런 식
fetch("some-valid-url", (response) => {
parseToJson(response, (json) => {
filterData(json, (filteredData) => {
console.log(filteredData);
});
});
});
Promise 덕분에 아래와 같이 indent depth가 증가하지 않게 작성할 수 있다.
fetch("some-valid-url")
.then(parseToJson)
.then(filterData)
.then(console.log);
내부에서 argument에 따라 계산하고 그 결과를 반환하는 명쾌한 행위와는 다르게,
외부(예: API, DB 등등)에 요청(혹은 메시지)를 보내고 응답을 받는 행위는 좀 복잡해요.
외부의 사정에 따라 응답이 늦게 올 수도 있고 아예 못 받을 수도 있거든요. 실제로 어떻게 될지는.. 기다려 봐야 아는 거죠.
그런데 기다리는 동안 다른 일을 못하면 손해잖아요? 요청은 보내 놨으니 일단 다음 작업으로 넘어가고 싶어요.
하지만 그냥 넘어가면 잊어버릴 테니 잊지 않도록 할 장치가 필요한데, 그게 Promise랍니다.
외부의 응답을 기다려야 하는 함수들은 응답을 받지 못했더라도 기다리지 않고 일단 Promise
를 반환하도록 해요. 그럼 그 함수를 호출하자마자 Promise
가 반환되면서 호출된 함수 실행이 끝나니까 다음 작업으로 넘어갈 수 있겠죠. 넘어가기 전에, 응답을 받았을 경우(또는 응답 받는 데 실패했을 경우)에 실행할 작업들을 반환된 Promise
의 .then()
메서드를 이용해서 미리 알려주고요.
( 참고로, '내가 할 일이 많아서 오래 걸리는 경우'와 '내가 할 일은 끝냈는데 다른 사람이 이어서 처리하는 걸 기다리느라 오래 걸리는 경우'는 달라요. Promise는 둘 중 뒤의 경우에 사용되는 거고요. )
Promise
간단히 Promise
를 하나 만들어 보자.
new Promise()
에는 함수 하나를 전달해야 한다. 그래서 아무 것도 하지 않는 익명 함수 하나(() => {}
)를 전달했다.PromiseState
에 보이는 것은 Promise
의 상태다.pending
(기다리고 있는 상태).PromiseResult
에 보이는 것은 실제 우리가 필요한 데이터다.pending
일 때는 result가 undefined
이고fulfilled
(기다림 후 원하는 걸 얻은 상태)가 되면 실제 데이터로 바뀔 것이다.rejected
(기다림 후 원하는 걸 얻지 못한 상태)가 될 수도 있다.new Promise()
에 전달한 것은 단지 함수 하나다.resolve
)를 통해서777
)fulfilled
로 바뀐다.아래는 이에 대한 공식 설명이다.
new Promise()
에 전달하는 함수는 Promise를 초기화하는 용도란다.resolve
)로 "resolve하는 함수"만 받았지만 사실 파라미터를 하나 더 추가해서 "reject하는 함수"도 같이 받을 수 있다.resolve(777);
) 값을 전달할 수 있지만Promise
를 전달할 수도 있다.Promise
인 경우 마찬가지로 그 Promise
가 바로 result가 되는 것은 아니다.Promise
가 resolve됐을 때의 result'다..then()
HTML 파일을 만들고 아래처럼 스크립트 코드를 넣은 후 실행하면 브라우저 개발자 도구 콘솔에 뉴스 기사들이 담긴 배열이 출력될 것이다.
<!DOCTYPE html>
<html lang="en">
<head></head>
<body></body>
<script>
function responseToJson(response) { // HTTP 응답을 받아 JSON 형식의 데이터를 반환하는 함수
return response.json();
}
function printJson(json) { // 데이터를 받아 콘솔에 출력하는 함수
console.log(json);
}
fetch("https://api.hnpwa.com/v0/news/1.json") // 1
.then(responseToJson) // 2
.then(printJson); // 3
</script>
</html>
fetch()
함수를 호출하여 외부 API에 데이터 요청..then()
에 함수 responseToJson
전달.Promise
의 상태가 fulfilled
가 되면 responseToJson
함수가 호출됨..then()
에 함수 printJson
전달.Promise
의 상태가 fulfilled
가 되면 printJson
함수가 호출됨..then()
또한 Promise
를 반환한다. 그래서 .then()
다음에 또 .then()
을 사용할 수 있는 것..then()
에 전달되는 함수는 값을 반환해도 되고 Promise
를 반환해도 된다..then()
에 전달되는 함수'의 첫 번째 파라미터 인자로 그 값이 전달된다.Promise
를 반환하는 경우, '다음 .then()
에 전달되는 함수'의 첫 번째 파라미터 인자로 전달되는 것은 반환된 Promise
자체가 아니라, 반환된 Promise
가 resolve됐을 때의 result다.new Promise((resolve) => {
resolve(777);
})
.then((num) => {
console.log(`first num: ${num}`);
return num;
})
.then((num) => {
console.log(`second num: ${num}`);
return new Promise((resolve) => {
setTimeout(() => {
resolve(num);
}, 2_000);
});
})
.then((num) => {
console.log(`third num: ${num}`);
});
출력:
first num: 777
second num: 777
(2초 후..)
third num: 1000