자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다.
하지만 전통적인 콜백 패턴은 일단 가독성이 나쁘다. 또한 비동기 처리 중 발생한 에러의 예외 처리가 곤란하며 여러 개의 비동기 처리 로직을 한꺼번에 처리하는 데에도 한계가 있다.
그리하여 ES6에서 비동기 처리를 위한 또 다른 패턴으로 Promise를 도입하였다. Promise는 전통적인 콜백 패턴이 가진 단점을 보완하며 비동기 처리의 시점을 명확하게 표현해 준다.
직렬적으로 task를 수행한다. 즉, 태스크는 순차적으로 실행되며 어떤 작업이 수행 중이면 다음 작업은 대기하게 된다.
예를 들어 서버에서 데이터를 가져와서 화면에 표시하는 작업을 수행할 때, 서버에 데이터를 요청하고 응답될 때까지 이후의 태스크들은 블로킹된다.
한 작업이 종료되지 않은 상태라 하더라도 대기하지 않고 즉시 다음 작업을 실행한다.
예를 들어 서버에서 데이터를 가져와서 화면에 표시하는 작업을 수행할 때, 서버에 데이터를 요청한 이후 서버로부터 데이터가 응답될 때까지 대기하지 않고(Non-Blocking) 즉시 다음 작업을 수행한다. 이후 서버로부터 데이터가 응답되면 이벤트가 발생하고 이벤트 핸들러가 데이터를 가지고 수행할 작업을 계속해 수행한다. 자바스크립트의 대부분의 DOM 이벤트와 setTimeout, setInterval 함수, Ajax 요청은 비동기식 처리 모델로 동작한다. 이는 다른 요청이 블로킹되지 않는 것이 장점이다.
하지만 비동기 처리를 위해 콜백 패턴을 사용하면 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 nesting되어 복잡도가 높아지는 Callback Hell이 발생하는 단점이 있다. 콜백 헬은 가독성을 나쁘게 하며 실수를 유발하는 원인이 되므로 지양하는 것이 좋다.
프로미스는 Promise 생성자 함수를 통해 인스턴스화한다. Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달받는데 이 콜백 함수는 resolve와 reject함수를 인자로 전달받는다.
Promise는 비동기 처리가 성공하였는지 또는 실패하였는지 등의 state 정보를 갖는다.
Promise 생성자 함수가 인자로 전달받은 콜백 함수는 내부에서 비동기 처리 작업을 수행한다. 이때 비동기 처리가 성공하면 콜백 함수의 인자로 전달받은 resolve 함수를 호출한다. 비동기 처리가 실패하면 reject 함수를 호출한다. 이 처리 결과는 Promise 객체의 후속 처리 메소드로 전달된다.
Promise로 구현된 비동기 함수는 Promise 객체를 반환하여야 한다. Promise로 구현된 비동기 함수를 호출하는 측(promise consumer)에서는 Promise 객체의 후속 처리 메소드(then, catch)를 통해 비동기 처리 결과 또는 에러 메시지를 전달받아 처리한다. Promise 객체는 상태를 갖는다고 하였다. 이 상태에 따라 후속 처리 메소드를 체이닝 방식으로 호출한다.
then 메소드는 두 개의 콜백 함수를 인자로 전달 받는다. 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출되고 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다.
then 메소드는 Promise를 반환한다.
예외(비동기 처리에서 발생한 에러와 then 메소드에서 발생한 에러)가 발생하면 호출된다. catch 메소드는 Promise를 반환한다.