Promise
#
Promise언젠가 끝나는 작업의 결과값을 담는 객체
#
Promise 객체 생성정적 메서드 Promise.resolve
Promise 객체의 프로퍼티
#
비동기 작업을 하는 Promise 객체 생성#
Promise 생성자- Promise 생성자의 인수 "콜백"
- executor(실행자, 실행 함수)
- new Promise 생성자로 프로미스가 만들어 질 때 자동으로 실행됨
- 콜백(Executor) 의 인수
- 자바스크립트 엔진이 미리 정의한 함수
resolve(value)
- 일이 성공적으로 끝난 경우 Executor 안에서 resolve(value) 를 호출
- (value)이 Promise 객체의 [[PromiseResult]] 값
reject(error)
- 에러 발생 시 에러 객체를 나타내는 error 와 함께 호출
#
Promise 객체의 내부 프로퍼티- state
[[PromiseState]]
- pending (대기) : 처음 값
- settled : 처리된 Promise
- fulfilled (이행) : resolve 가 호출 될 때
- rejected (거부됨) : reject 가 호출 될 때
- result
[[PromiseResult]]
- undefined : 처음 값
- value :
resolve(value)
가 호출 될 때 - error :
reject(error)
가 호출될 때
#
Promise 핸들러 .then/catch/finally처리된 Promise 핸들러는 즉각 실행된다.
.then/catch/finally 핸들러는 Promise 가 처리되길 기다린다.
Promise 가 이미 처리된 상태라면 즉각 실행된다.
#
Promise Executor 와 Handler 의 Error 처리보이지 않는 try..catch 가 있다.
- 예외를 잡고 이를 reject 처럼 다룬다.
- 제어의 흐름이 가장 가까운 에러 핸들러로 넘어간다.
#
then- Promise 결과값에 대한 추가 작업
- Promise 객체에 then 메서드를 사용할 수 있다.
#
then 인자- 첫번째 인수. Promise 가 이행되었을 때 실행하는 함수
- 두번째 인수. Promise 가 거부되었을 때 실행하는 함수
콜백의 첫번째 인수 : Promise 객체의 [[PromiseResult]]
#
then 메서드의 반환 값Promise 객체
#
then 메서드의 return 값Promise 객체의 [[PromiseResult]] 값
#
catch에러가 발생한 경우만 다루고 싶을 때
- null 을 then 의 첫번째 인수로 전달한다.
.then(null, errorHandlingFunction)
.catch(errorHandlingFunction)
두가지 방식은 똑같이 동작한다.
에러가 성공적으로 처리되면, 가장 가까운 곳에 있는 .then 핸들러로 제어흐름이 넘어가 실행이 이어진다.
에러가 성공적으로 처리되지 않았을 때, 에러를 다시 던진다.
#
unhandledrejection거부된 Promise 를 처리하지 못할 경우 자바스크립트 엔진은 전역 에러를 발생시킨다.
브라우저 환경에선 이런 에러를 unhandledrejection
이벤트로 잡을 수 있다.
- 처리되지 않은 에러 추적
- 이런 에러를 사용자(혹은 서버)에게 알려서 앱이 아무런 설명없이 '그냥 죽는걸' 방지한다.
#
setTimeout 에서의 에러모든 동기적 에러는 try..catch 에서 처리되지만 setTimeout 은 Executor 가 끝난 후 발생하기 때문에 Promise 에서 에러를 처리할 수 없다.
#
finallyPromise 처리가 완료되면, 결과와 상관없이 finally 문이 실행된다.
finally 핸들러(콜백의 이름)
- 인수가 없다.
- Promise 의 settled 상태를 알 수 없다
- 자동으로 다음 핸들러에 결과와 에러를 전달한다.
#
HTTP 통신의 Promiseaxios.get()
함수는 Promise 객체를 반환한다.
콜백의 비동기 프로그래밍의 예시와 코드를 비교해 보자
앞서 콜백으로 구현된 loadScript 를 Promise 로 나타내어 봅시다.
#
Promise.all(iterable)여러 프로미스의 결과를 집계할 때 사용한다.
#
매개변수iterable
객체
- 프로미스 생성자
- 프로미스가 아닌 값
- 이미 이행된 프로미스 객체
#
반환 값- iterable 의 Promise 가 모두 처리됨
- 새로운 Promise 를 이행
[[PromiseResult]]
#
새로운 Promise 의 이행 값 - iterable 의 Promise 들의
[[PromiseResult]]
을 담은 배열
#
이미 이행된 프로미스 iterable : 비동기성이미 이행된 프로미스로 배열 에서는 Promise.all 의 비동기성
이 나타난다.
#
Promise.all() reject : 비동기성- reject 가 발생해도 취소되지 않고, 나머지 Promise 도 결과를 산출하지만 무시된다.
- AbortController 를 사용하면 프로미스 취소가 가능하다.
#
빈 iterable : 동기성이미 이행한 Promise 객체 반환
#
프로미스가 없는 iterable : 비동기성크롬 58 경우 이미 이행한 프로미스 반환
#
빈 || 프로미스가 없는 iterable 이 아닌 경우.Promise 가 모두 이행 된 후, 새 Promise 객체를 반환한다.
#
예시복수의 URL 에 동시에 요청을 보내고, 다운로드가 모두 완료된 후에 콘텐츠를 처리할 때.
#
Promise.allSettled여러 요청 중 하나가 실패해도 다른 요청 결과는 반환한다.
- 모든 Promise 가 처리될 때까지 기다린다.
#
Promise.race(iterable)#
반환 값대기중인 Promise 객체를 반환 ([[PromiseResult]]
를 비동기적으로 전달받음)
[[PromiseResult]]
iterable 에서 처음으로 이행하거나 거부한 프로미스 객체의 값
#
이미 이행된 프로미스 객체 iterable : 비동기성#
빈 iterable반환한 Promise 는 영원한 pending 상태
#
프로미스가 아닌값, 이미 완료된 프로미스객체가 있는 iterable : 비동기성이러한 값들 중 처음으로 등장하는 값을 결과값으로 이행
#
Promise.resolve(value)result 가 value 인 이행 상태 프라미스 객체 생성
let promise = new Promise(resolve => resolve(value));
와 동일
function loadCached(URL)
- URL 을 대상으로 fetch 를 호출하고, 그 결과를 기억(cache)합니다.
- 동일한 URL 을 대상으로 fetch 를 호출하면, Promise.resolve 를 사용해 캐시 된 내용을 Promise 로 만들어 반환 값이 항상 Promise 가 되게 합니다.
- loadCached 를 호출하면 프라미스가 반환된다는 것이 보장되기 때문에 loadCached(url).then(…)을 사용할 수 있습니다.
#
Promise.reject(error)result 가 error 인 거부상태 Promise 생성
let promise = new Promise((resolve, reject) => reject(error));
와 동일
#
프로미스화 Promisification콜백을 받는 함수를 Promise 를 반환하는 함수로 바꾸는 것
- JavaScript es6 에서 promise 를 표준으로 채택하면서 대부분의 브라우저에서 Promise 를 사용하게 됨
- 콜백 보다는 Promise 가 더 편리하다.
- 콜백기반 라이브러리를 Promise 를 반환하는 함수로 바꿀 수 있다.
- Node.js 내장 함수
util.promisify
- 모듈
es6-promisify
- async await 의 장점을 이용할 수 있다.
- 최신브라우저에서, async 를 남발해도 성능의 큰 차이가 없다. native function 과 가깝다.
- 비동기 기능이 있는 어떤함수로 만들어도 promise 로 만들어 놓는게 중요하다.
#
콜백의 setTimeout 을 Promise 로 만들기res(f())
f
의 리턴값을[[PromiseResult]]
으로 가지는 Promise 객체
#
마이크로 태스크#
마이크로태스크 큐 (PromiseJobs)비동기 작업을 처리하기 위한 PromiseJobs 라고 불리는 내부 큐(internal queue).
V8 엔진에서는 microtask queue 라고 부른다.
- FIFO
- 실행할 것(호출 스택)이 비었을 때만 마이크로태스크큐의 작업이 실행된다.
#
Promise 핸들러 .then/catch/finallyPromise 가 즉시 이행되더라도, Promise 핸들러 .then/catch/finally 는 항상 비동기적으로 실행된다.
- Promise 객체가 준비됨
- Promise 객체의
.then/catch/finally
핸들러가 PromiseJobs 큐에 들어간다 (실행전)
#
PromiseJobs 큐가 실행되는 조건- 현재 코드의 실행이 완료될 때
- 큐에 적재된 이전 핸들러의 실행이 완료될 때
브라우저/Node.js를 포함한 대부분의 자바스크립트 엔진에서, 마이크로태스크가 '이벤트 루프(event loop)'와 '매크로태스크(macrotask)'와 깊은 연관 관계를 맺는다. 이 부분에 대해서는 주제 브라우저 에서 다시 다룰 것이다. TODO
#
처리되지 못한 거부 unhandledrejection마이크로 태스크(PromiseJobs) 큐 끝에서 거부된 Promise 가 처리되지 못할 때 발생
- 자바스크립트 엔진은 전역 에러를 발생시킨다.
에러가 잘 처리되었으므로 실행되지 않습니다.
setTimeout 을 이용하여 에러를 나중에 처리할 경우
unhandledrejection
은 마이크로태스크 큐에 있는 작업 모두가 완료되었을 때 생성됨..catch
는unhandledrejection
이 발생한 이후에 트리거 된다.
무슨이유에서인지 브라우저 콘솔에서 실행을 해 보아도 'unhandledrejection'이벤트는 발생하고 있지 않다. (TODO)
#
Promise 장점then
콜백을 중첩하지 않고도 비동기 작업을 연이어 할 수 있다.- 비동기 작업을 값으로 다룰 수 있다.
Promise | Callback |
---|---|
흐름이 자연스럽다. loadScript(script) 로 스크립트를 읽고, 결과에 따라 그 다음에 (then) 무엇을 할지에 대한 코드를 작성할 수 있다. | loadScript(script, callback) 을 호출할 때, 미리 callback 함수가 준비되어 있어야 한다. |
원하는 만큼 then 호출 가능. | 콜백은 하나만 가능하다. |
#
Promise 의 비판- 여전히 콜백을 사용한다.
- 여전히 가독성이 좋지 않다.
#
thenable 객체를 반환하는 핸들러Promise 를 상속받지 않고도, 커스텀 객체를 사용해 프라미스 체이닝을 만드는 방법
#
thenable 객체.then 메서드를 가진 객체
- 서드 파티 라이브러리가 Promise 호환 가능 객체를 구현할 수 있다는 점에서 등장