비동기 프로그래밍
- 싱글스레드
- 한번에 하나의 스크립트만 실행 가능
- Queue 로 관리
→ 결국 오래걸리는 작업은 비동기로 처리해야 함. - ES5 까지 비동기 처리를 위한 2가지 패턴
- callback
- event handler
callback 이나 event 방식 결국 동일한거 아닌가?
Event 방식
- 이슈
1. 모든 비동기 처리 블록에 대한 개별적인 Exception 처리 필요
2. Nested function call 에 의해 코드읽기가 어려움
3. 다른 파트에서 비동기 동작에 대한 상태관리를 하기 위해서 별도 변수를 관리해야 함 → 상태 관리 어려움
Callback 방식
성공 실패시 전달된 success 혹은 error callback 으로 결과를 알려줌.
- 이슈
- Event 방식과 동일
두 가지 방식(Event, Callback) 모두 중첩된 Ajax 혹은 다른 비동기 작업이 추가 되는 경우 복잡도가 증가
Promise
- 위 이슈를 해결하고자 ES6 에 도입
1. 개별적인 Exception 처리 불편
2. Nested Function Call 에 의한 코드 읽기 어려움
3. 비동기 동작에 대한 상태관리 - 이미 다른 언어 (Java — Future, C# 5, C++ 11, Swift, Scala …)에서 도입, Since 1976
Promises 생성자
비동기 처리를 수행할 내용이 있는 callback(executor) 를 파라미터로 받고 executor 는 resolve 와 reject 를 인자로 받는다.
- resolve : 비동기 작업이 성공적으로 수행시 호출되는 Callback 함수
- reject: 비동기 작업이 실패한 경우 호출되는 Callback 함수
Promise 의 상태값
위 resolve/reject 호출에 따라 다음과 같은 4개의 상태값으로 구분할 수 있다.
- Fulfilled: resolve(non-Promise object or no arguments) 로 호출된 경우
- Rejected: reject 가 호출되거나 executor 안에서 예외가 발생한 경우
- Pending: resolve 혹은 reject 가 아직 호출되지 않은 상태
- Settled: fulfilled 되거나 rejected 된 경우(pending 되지 않은 상태)
한번 fulfilled 되거나 rejected 되면 결과를 되돌릴 수 없다.
Promise 객체를 인자로 resolve 가 호출된 경우 Promise Object 는 전달된 Promise 의 상태를 따른다.
fulfillment value
즉 resolve 의 파라미터
- 해당 값이 Promise 가 아닌 경우 그 값 자체가 Promise 객체의 fulfillment value 로 처리
- 아무것도 전달되지 않은 경우 value 는 undefined,지만 Promise 는 fulfilled 되었다고 간주
- Promise 객체가 전달된 경우 전달된 Promise 객체가 fulfilled 된 경우에 fulfilled 된 값이 fulfillment value 가 된다.
마찬가지로 전달된 Promise 객체가 reject 된 경우 Reason 은 전달된 Promise 객체의 reject Reason 과 동일하다.
then(onFulfilled, onRejected)
Promise 객체의 then 메소드
Promise 가 fulfilled 혹은 reject 된 후 후처리를 할 수 있게 해준다.
2개의 파라미터
- onFulfilled
- Promise 객체가 fulfilled 되었을 때 호출되는 callback
- 인자는 Promise 객체의 fulfillment value - onRejected
- Promise 객체가 rejected 되었을때 호출되는 callback
- executor 범위(scope) 안에서 exception 이 발생한 경우에도 호출됨
then()메소드에 전달되는 callback 은 비동기적으로 처리된다.
아래와 같은 promise 객체를 생략한 형태로 많이 쓴다. 이런 스타일을 통해 가독성을 높인다.
then() 은 항상 새롭게 생성된 promise 객체를 반환한다. 이 객체는 callback 의 반환 값을 resolve 한다.
다음은 then() 에서 새롭게 생성된 promise 객체가 어떻게 반환되는지를 설명한다.
onFulfilled Callback 의 종류에 따른 처리 방식
- callback = onFulilled (no return)
→ 내부적으로 새로운 fulfilled Promise가 생성/반환
→ 인자 없이 resolve - callback =onFulfilled (return ‘custom Promise’)
→ 내부적으로 새로운 Promise객체 생성/반환
→ (이 객체는) ‘custom Promise’를 resolve
위에서 Promise 객체를 resolve 하면 어떻게 된다고 했죠?
- callback = onFulfilled (return !‘custom Promise’)
→ 내부적으로 새로운 Promise 객체 생성/반환
→ 위의 반환값을 resolve - callback = null
→ onFulfilled 이 내부적으로 생성되어 null 을 대체
→ 내부적으로 새로운 Promise 객체 생성/반환
→ 부모 Promise 의 fulillment value 와 동일하다.
onRejected Callback 의 종류에 따른 처리 방식
- callback = onRejected (no return)
→ 내부적으로 새로운 Promise 객체 생성/반환
→ 인자 없이 resolve - callback = onRejected (return ‘custom Promise’)
→ 내부적으로 새로운 Promise 객체 생성/반환
→ ‘custom Promise’를 resolve - callback = onRejected (return !‘custom Promise’)
→ 내부적으로 새로운 Promise 객체가 생성/반환
→ (이 객체가) 위 반환값을 resolve - callback = null or 생략
→ onRejected Callback 이 자동 생성
→ (이 callback은) 새로운 rejected Promise 객체를 반환
→ rejection 의 reason 은 부모 Promise 객체의 reason 과 동일
다음은 다중 체이닝 실행이 어떻게 되는지 보여주는 그림이다.
https://mdn.mozillademos.org/files/8633/promises.png
catch(onRejected)
에러만을 다룰 때 then() 대신 사용되는 함수 (단지 그것뿐. 가독성 향상)
항상 새로운 promise 객체가 생성되며 다음은 그 생성 방식이다.
onRejected 의 반환값에 따라
- no return → 새로운 fulfilled Promise 를 내부적으로 생성/반환
- return custom Promise → 새로운 Promise 객체가 내부적으로 생성/반환 → (이 객체는) custom Promise 객체를 resolve
- return !custom Promise → 새로운 Promise 객체가 내부적으로 생성/반환 → (이 객체는) return value 를 resolve
- null 혹은 생략 → onRejected 가 내부적으로 생성되어 null 을 대체 → (이 콜백은) rejected Proimse 객체를 반환, reason 은 부모를 따른다.
- catch 가 수행될 promise 객체가 fulfilled 되면, catch()는 그냥 새로운 fulfilled promise 객체를 반환하고, onRejected 는 무시한다. fulfillment value 는 부모를 따른다.
Promise.resolve(value)
value 를 resolve 하는 Promise 객체를 반환한다.
- value 를 Promise 객체로 변환하기 위해 사용
- value 가 Promise 객체인지 불확실 할때 사용하면 유용
- eg. ES6 의 Promise 와 다른 인터페이스를 갖는 jQuery Promise 를 ES6 로 변환
Promise.reject(value)
value 를 reason 으로 한 rejected Promise 를 반환한다.
디버깅용으로 사용. (resolve 와 목적이 다름)
Promise.all(iterable)
Promise 객체 리스트(iterable)이 fulfilled 되었을때 fulfilled 되는 Promise 객체를 반환한다.
만약 iterable 리스트에 Promise 객체가 아닌 값이 있는 경우 Promise.resolve() 에 의해 Promise 로 변환된다.
여러 개의 비동기 작업들이 완료된 후 해야할 작업이 있을 때 유용
Rejected 되는 경우, 실패 즉시 rejected Promise 객체를 반환하고 실패한 Promise 의 reason 을 reason 으로 사용한다.
Promise.race(iterable)
Promise 객체 리스트(iterable) 중 가장 먼저 fulfilled 혹은 rejected 되는 Promise 객체를 반환한다.