JavaScript는 비동기 처리를 할 때 콜백 함수를 사용한다. 하지만 함수 호출이 중첩되면서 가독성이 떨어져 코드를 이해하는데 어려움이 생기고 복잡도가 증가하였다. 콜백 지옥에서 벗어날 수 있도록 ES6에서 Promise
가 등장했다. 프로미스는 성공적으로 수행된다면 그 결괏값을, 실패한다면 에러를 전달한다. 코드를 간결하게 만들어 처리의 성공과 실패를 더욱 쉽게 관리할 수 있기 때문에 프로미스를 사용한다.
프로미스는 제작 코드와 소비 코드로 이루어져 있다. **제작 코드(Producing code)**는 정보를 전달하는 코드로 네트워크에서 사용자 데이터를 로드하는 코드이다. **소비코드(Consuming code)**는 생산 코드가 전달한 정보를 받는 코드로 로드된 사용자 데이터를 받는 코드이다.
예를 들어 놀이동산에 갔다고 가정해보자. 인기 있는 놀이기구는 기다리는 줄이 길어 몇 시간씩 기다려야 한다고 한다. 그래서 시간별로 예약받는데 휴대폰 번호를 적고 가면 탑승 가능한 시간에 알림을 보내준다고 한다.
예약한 손님이 탑승할 수 있는 시간까지 시간이 걸리는 ‘놀이기구’가 제작코드이다. 놀이기구를 탈 수 있다고 알림을 받는 ‘손님’이 소비코드이다. 예약한 손님의 차례가 왔을 때 탑승 알림을 보내는 것이 프로미스로 제작코드와 소비코드를 연결해 준다.
const 프로미스 = new Promise(function(resolve, reject) {
// 실행함수
});
먼저 new 연산자를 사용해 프로미스 객체를 만든다. 생성자 함수 new Promise()
의 매개변수로 작성하는 함수를 **실행 함수(excutor)**라고 한다. 실행 함수는 resolve(), reject()를 매개변수로 받는다. 따로 만들지 않은 resolve()
와 reject()
가 어떻게 사용될 수 있나 싶지만, Promise
가 만들어질 때 자바스크립트 엔진에 의해 자동으로 실행된다. resolve()는 비동기 작업이 성공적으로 처리되었을 때 결괏값(최종 데이터)과 함께 호출되고, reject()는 실패했을 때 에러 객체를 전달한다.
const 프로미스 = new Promise(function(resolve, reject) {
resolve('🍓');
resolve('🍌');
});
console.log(프로미스);
반드시 실행 함수는 resolve(), reject() 둘 중 하나를 호출해야 한다. resolve()나 reject()를 각각 중복해서 호출하면 처음 호출한 게 적용되고 그 이후의 호출된 함수들은 무시된다.
프로미스 객체는 비동기 작업에 대한 상태와 결과를 관리한다. 프로미스가 생성된 직후에는 보류, 즉 pending이라는 상태를 갖는다. 그 이후 비동기 작업의 성공 여부에 따라 fulfilled 혹은 rejected라는 상태를 갖게 된다. 비동기 처리가 성공적으로 이행되어 resolve()
가 호출되면 pending에서 fulfilled 상태로 전환되며, 만약 처리 도중 에러가 발생해 reject()
가 호출되면 pending에서 rejected 상태로 전환된다. 이렇게 pending에서 fulfilled 혹은 rejected로 바뀌면 settled(해결된, 안정된) 상태가 되었다고 말하며, 한번 상태가 정해지면 다른 상태로 절대 변경될 수 없다. 프로미스는 하나의 결과를 갖기 때문이다.
프로미스의 상태와 결과는 콘솔창에서 내부 슬롯을 통해 확인할 수 있다.