Bleeding edge

2022/09/01 - TIL 본문

ConnecTo

2022/09/01 - TIL

codevil 2022. 9. 1. 17:17

45장 프로미스

전통적인 콜백은 가독성이 나쁘고, 비동기 처리 중 발생한 에러의 처치가 곤란하며, 여러개의 비동기 처리를 한번에 처리하는데도 한계가 있다. ⇒ 이를 개선하기위해 비동기 처리를 위한 프로미스를 도입했다.

45.1 비동기 처리를 위한 콜백 패턴의 단점

setTimeout 함수가 비동기함수인 이유는 콜백 함수의 호출이 비동기로 동작하기 때문이다. setTimeout 함수를 호출하면 콜백 함수를 호출 스케줄링 한다음 타이머 id를 반환하고 즉시 종류한다. setTimeout 함수의 콜백 함수에서 상위 스코프의 변수에 값을 할당해보자. setTimeout 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머 id를 반환하므로 콜백 함수에서 값을 반환하는 것은 무의미하다.

[ ] 비동기 함수인 이유는 [ ]함수의 콜백 함수가 비동기로 동작하기 때문이다. 그리고 undefined를
호출 하고 종료한다.

비동기 함수는 비동기처리 결과를 외부에 반환할 수 없고 상위 스코프의 변수에 할당할 수도 없다. 따라서 비동기 함수의 처리 결과에 대한 후속처리는 비동기 함수 내부에서 수행해야한다. 이때 비동기 함수를 범용적으로 사용하기 위해 비동기 함수에 비동기 처리 결과에 대한 후속처리를 수행하는 콜백함수를 전달하는 것이 일반적이다. 필요에 따라 비동기 처리가 성공한다면 호출될 콜백함수와 비동기 처리가 실패하면 호출될 콜백함수를 전달할 수 있다

45.1.1 콜백헬

GET요청을 통해 서버로부터 응답을 취득하고 이데이터를 사용하여 또다시 GET요청을 한다
콜백 헬은 가독성을 나쁘게 하며, 실수를 유발하는 원인이 된다.
try 먼저실행
catch 에러시 실행
finally 어쨌든 실행

try는 setTimeout에서 나가서 콜스택에서 테스크 큐로가지만 catch는 이동되지 않기 때문에 실행되지 않는다.

비동기 처리를 위한 콜백 패턴은 콜백 헬이나 에러 처리가 곤란하다. 이를 극복하기 위해 Es6에서 프로미스가 도입되었다.

45.1.2에러 처리의 한계

비동기 처리를 위한 콜백 패턴의 문제점 중에서 가장 심각한 것은 에러처리가 곤란하다는 것이다.

45.2 프로미스의 생성

Promise는 호스트 객체가 아닌 ECMAScript 사양에 정의된 표준 빌트인 객체다. 이 콜백 함수는 resolve와 reject 함수를 인수로 받는다

pending  프로미스가 생성된 직후 기본 상태(비동기 처리가 아직 미수행)
fulfilled resolve 함수 호출(비동기 처리 수행)
rejected reject 함수 호출(비동기 처리 실패)

resolve나 reject가 되면 더 이상 상태 변화를 할 수 없다

프로미스는 비동기처리 상태와 처리 결과를 관리하는 객체다.

45.3 프로미스의 후속 처리 메서드

프로미스가 settled가 되어 상태를 변화할 수 없을때가 되면, then, catch finally를 제공한다.

프로미스의 비동기 처리 상태가 변화하면 후속 처리 메서드에 인수로 전달한 콜백 함수가 선택적으로 호출된다.

프로미스의 비동기 처리 상태가 변화하면 후속 처리 매서드에 인수로 전달한 콜백함수가 선택적으로 호출된다.

모든 후속처리 메서드는 프로미스를 반환하며, 비동기로 동작한다.

45.3.1 Promise.prototype.then

then함수는 두개의 콜백 함수를 인수로 전달받는다.

첫 번째 콜백함수는 fulfill 상태가 되면 호출한다. 두 번째 콜백함수는 rejected 상태가 되면 호출한다

콜백 함수가 프로미스가 아닌 값을 반환하면 그값을 암묵적으로 resolve 또는 reject하여 프로미스를 생성해 반환한다

45.3.2 Promise.prototype.catch

catch는 프로미스가 rejected 상태인 경우에만 호출한다

45.3.3 Promise.prototype.finally

프로미스의 성공또는 실패 여부와는 상관없이 한번 호출된다.

45.4 프로미스의 에러 처리

promiseGet('<https://jsonplaceholder.typicode.com/todos/1>').then(
	res=>console.xxx(res),
	err=>console.error(err)
)//두번째 콜백함수는 첫번째 콜백 함수에서 발생한에러를 잘못찾는다
.catch(err=> console.error(err));// then 메서드에 두번쨰 콜백 함수를 전달하는 것보다
//catch메서드를 사용하는것이 가독성이 좋고 명확하다. 

45.5 프로미스 체이닝

비동기 처리결과를 전달받아 후속처리를하므로 비동가 처리를 후속으로 처리할 수 있다

45.6 프로미스의 정적 매서드

45.6.1 Promise.resolve /Promise.reject

45.6.2 Promise.all

여러개의 비동기 처리를 모두 병렬 처리할때 사용된다

45.6.3 Promise.race

Promise.all 메서드처럼 이터러블을 인수로 전달받는다. 대신, 가장 먼저 fulfuill 상태가 된 프로미스의 처리 결과를 resolve하는 프로미스를 반환한다. 이때 첫번째 값이 rejected라면 모든 race의 메서드는 모두 reject된다

45.6.4 Promise.allSettled

모든 결과가 settled가 된다면 모든 처리결과를 배열로 반환한다. fulfill 상태인 경우 value 프로퍼티를 갖고 reject인경우 reason 프로퍼티를 가진다

45.7 마이크로태스크 큐

프로미스의 후속 처리 메서드의 콜백 함수는 태스크 큐가 아니라 마이크로태스크 큐에 저장되기 떄문에, setTimeout 함수보다는 먼저 결과 값이 나온다.

마이크로태스크 큐는 태스크큐보다 우선순위가 높다

45.8 fetch

fetch함수는 XMLHttpRequest 객체보다 사용법이 간단하고 프로미스를 지원하기 때문에 비동기 처리를 위한 콜백 패턴의 단점에서 자유롭다. fetch 함수에는 HTTP 요청에 전송할 URL와 HTTP 요청 메서드, HTTP요청 헤더, 페이로드 등을 설정한 객체를 전달한다.

fetch함수가 반환하는 프로미스는 기본적으로 404 Not Found나 500 Internal Server Error와 같은 HTTP 에러가 발생해도 에러를 reject하지 않고 불리언 타입의 ok 상태를 false로 설정한 Response 객체를 resolve한다. 오프라인 등의 네트워크 장애나 CORS에러에 의해 요청이 완료되지 못한 경우에만 프로미스를 REJECT한다

참고로 axios는 모든 HTTP에러를 reject하는 프로미스를 반환한다. 따라서 모든 에러를 catch에서 처리할 수 있어서 편리하다

46장 제너레이터와 aync/await

46.1 제러레이터란?

ES6에서 도입된 제너레이터는 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수다.

함수 호출자에게 함수 실행의 제어권을 양도할 수 있다
함수 호출자와 함수의 상태를 주고 받을 수 있다
제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.

46.2 제너레이터 함수의 정의

애스터리스크의 위치는 function키워드와 함수 이름 사이라면 어디든 상관없다

제너 레이터 함수는 생성자 함수나, 화살표 함수로 정의할 수 없다

46.3 제너레이터 객체

제너레이터 함수가 반환한 제너레이터 객체는 이터러블 이면서 동시에 이터레이터다.

제너레이터 함수가 반환한 제너레이터 객체는 이터러블 이면서 동시에 이터레이터다.

46.4 제너레이터의 일시 중지와 재개

제너레이터는 yeild 키워드와 next 메서드를 통해 실행을 중지했다가 필요한 시점에
다시 재개할 수 있다. 일반 함수는 호출 이후 제어권을 함수가 독점하지만 제너레이터는
함수 호출자에게 제어권을 양도하여 필요한 시저에 함수 실행을 재개할 수 있다.

일반 함수처럼 한번에 코드 블록의 모든 코드를 일괄 실행하는 것이 아니라 yield 표현식까지만
실행한다.(이때 함수의 제어권이 호출자로 양도된다) yield 키워드는 제너레이터 함수의 실행을 
일시 중지시키거나 yield 키워드 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 
반환한다. 함수 호출자는 next 메서드를 통해 yield 메서드에 인수를 전달해서 제너레이터 객체에
상태를 밀어넣을 수 있다. 이러한 제너레이터의 특성을 활용하면 비동기 처리를 동기 처리처럼
구현할 수 있다. 이에 대해서는 비동기 처리에서 자세히 살펴보자

46.5 제너레이터의 활용

46.5.1 이터레이블의 구현

제너레이터 함수를 사용하면 프로토콜을 준수해 이터러블을 생성하는 것보다 간단하게 이터러블을 구현할 수 있다.

46.5.2 비동기 처리

next yield 표현식을 통해 함수 호출자와 함수의 상태를 주고받을 수 있다

46.6 async/await

제너레이터를 사용해서 비동기 처리를 동기 처리처럼 동작하도록 구현하였지만 코드가 무척 장황해지고 가독성도 나빠졌기 때문에 ES8부터는 제너레이터보다 간단하고 가독성 좋게 비동기처리를 동기처리처럼 동작할 수 있도록 async/await가 등장하였다. async/await를 사용하면 프로미스의 then/catch/finally 후속처리 메서드에 콜백 함수를 전달해서 비동기 처리 결과를 후속처리할 필요 없이 마치 동기 처리 처럼 프로미스를 사용할 수 있다.

46.6.1 async 함수

await 키워드는 반드시 async 함수 내부에서 사용해야 한다. async 함수는 암묵적으로 반환 값을 resolve하는 프로미스를 반환한다.

constructor 메서드는 async 메서드가 될 수 없다. 클래스의 constructor 메서드는 인스턴스를 반환해야 하지만 async 함수는 언제나 프로미스를 반환해야 한다.

46.6.2 await 키워드

프로미스가 settled 상태가 될때까지 대기한다. 프로미스가 settled 상태가 되면 프로미스가 resolve한 처리 결과가 res 변수에 할당하게 된다. await 키워드는 다음 실행을 일시 중지시켰다가 프로미스가 settled 상태가 되면 다시재개한다.

'ConnecTo' 카테고리의 다른 글

2022/09/05 - TIL  (0) 2022.09.05
2022/09/02 - TIL  (1) 2022.09.02
2022/08/31 - TIL  (0) 2022.08.31
2022/08/30 - TIL  (0) 2022.08.30
2022/08/29 - TIL  (0) 2022.08.29