[딥다이브 스터디] 프로미스

dana·2022년 6월 27일
1

deepdive study

목록 보기
8/8
post-thumbnail

45. 프로미스

자바스크립트의 비동기 처리 패턴 -> 콜백함수
전통적인 콜백 패턴은 콜백 헬로 인해
1. 가독성이 나쁘고
2. 처리 중 발생한 에러의 처리가 곤란
3. 여러개의 비동기처리를 한 번에 실행하는데 한계

이러한 단점들을 보완하기 위해 es6에서 프로미스를 도입

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

45.1.1 콜백 헬

const get = url => {
    const xhr = new XMLHttpRequest();
    
    xhr.open('GET', url);
    xhr.send();
    
    xhr.onload = () => {
        if (xhr.status === 200){
            //서버의 응답을 콘솔에 출력
            console.log(JSON.parse(xhr.response))
        } else {
            console.error(`${xhr.status} ${xhr.statusText}`)
        }
    }
};

get('API_ENDPOINT');

// 결과값 출력

get 함수는 비동기 함수
비동기 함수를 호출 시, 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다고 해도 기다리지 않고 즉시 종료.
그렇기 때문에 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않음.

(( 예시 1 ))

let res; 

const get = url => {
    const xhr = new XMLHttpRequest();
    
    xhr.open('GET', url);
    xhr.send();
    
    xhr.onload = () => {
        if (xhr.status === 200){
            //서버의 응답을 콘솔에 출력
           res = JSON.parse(xhr.response)
           return JSON.parse(xhr.response)
            
        } else {
            console.error(`${xhr.status} ${xhr.statusText}`)
        }
    }
};

const response = get('API_ENDPOINT');
console.log(response) // undefined
console.log(res) // undefined

이벤트 핸들러에서의 반환은 의미가 없다.

비동기 함수의 실행 순서
1. 일단 태스크큐에 저장되어 대기
2. 콜스택이 비면 이벤트 루프에 의해 콜스택으로 푸쉬되어 실행

이벤트 핸들러가 실행되는 시점에는 콜스택이 빈 상태여야 함.
따라서 비동기 함수의 처리 결과에 대한 후속 처리는 비동기 함수 내부에서 수행

후속처리를 위한 비동기 함수가 또 비동기적인 결과를 가지고 후속처리에 의한 후속처리에 의한 후속처리..
== 콜백 헬

get('/step1', a => {
    get('/step2', b => {
        get('/step3', c => {
            ....
        })
    }) 
})

45.1.2 에러 처리의 한계

((예시 2))

setTimeout은 비동기함수이므로 콜백함수가 호출되는 것을 기다리지 않고 바로 종료

() => { throw new Error('Error!'); }
// 콜백함수를 호출하는 대상이 setTimeout이 아니게 됨.

에러는 호출자 방향으로 전파되기 때문에 catch에서 걸리지 않음.

45.2 프로미스의 생성

new Promise -> 프로미스 객체 생성 (표준 빌트인 객체)
콜백함수를 인수로 전달받으며, 이 콜백함수는 resolve와 reject 함수를 인수로 전달받음.

const promise = new Promise((resolve, reject) => {
    if(성공시){
        resolve();
    }else{
        reject();
    }
})

프로미스는 비동기 처리가 어떻게 진행되는지에 대한 상태 정보를 가짐

pending -> 성공 시 fulfilled / 실패 시 rejected (settled 상태로 변화)

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

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

45.3.1 Promise.prototype.then

두 개의 콜색함수를 인수로 전달
1. 비동기 성공 시 실행되는 콜백 함수
2. 비동기 실패 시 실행되는 콜백 함수

then 메서드는 언제나 promise를 반환
(프로미스가 아닌 값을 반환해도 암묵적으로 프로미스를 생성해 반환)

45.3.2 Promise.prototype.catch

한 개의 콜백함수를 인자로 받으며, 프로미스가 rejected일 때 호출

45.3.3 Promise.prototype.finally

한 개의 콜백함수를 인자로 전달받으며, 프로미스의 성공 여부와 관계없이 무조건 호출

45.4 프로미스의 에러 처리

then메서드의 두번째 콜백함수로 처리하거나 catch를 이용해 처리 가능

promise(비동기 실행)
.then(
    res => console.log(res),
    err => console.err(err)
)

promise(비동기 실행)
.catch(
    err => console.err(err)
)
// catch를 실행하면 내부적으로 then( _, rejected)처럼 동작

catch를 사용하는 것이 가독성이 더 좋고, then에서 비동기 함수 외에도 에러가 발생하는 경우를 케어할 수 있어 권장

45.5 프로미스 체이닝

비동기 처리를 위한 콜백 패턴은 콜백 헬이 발생하는 문제가 있음
프로미스에 대한 결과를 이용해 비동기 작업을 이어나가는 것을 프로미스 체이닝이라고 하는데, 프로미스는 비동기 결과를 받아 후속처리를 하기 때문에 콜백 헬이 발생하지 않음.
다만 콜백 함수를 사용하지 않는 것은 아니라 이를 보완하기 위해서 async, await가 등장함.

-> 다음 발표^^*

45.6 프로미스의 정적 메서드

45.6.1 Promise.resolve/ Promise.reject

이미 존재하는 값을 래핑해 프로미스를 생성하기 위해 사용

const resolvePromise = Promise.resolve([1,2,3]);
resolvePromise.then((res) => console.log(res));

const resolvePromise = new Promise(resolve => resolve([1,2,3]))
resolvePromise.then((res) => console.log(res))

45.6.2 Promise.all

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

배열로 전달받은 배열의 모든 프로미스가 fulfilled 상태가 되면 종료
모든 프로미스가 fulfilled 상태가 되면 결과를 순서대로 배열에 저장해 resolve하는 새로운 프로미스를 반환

all의 인수로 전달되는 배열에 프로미스가 아닌 요소가 들어가더라도, 프로미스로 래핑되어 실행됨.

중간에 하나라도 rejected를 반환하면 다른 프로미스의 반환 여부와 관계없이 reject를 반환

45.6.3 Promise.race

promise.all처럼 프로미스를 배열로 갖지만, 모든 결과값을 기다렸다가 배열로 리턴되는 all과 달리 가장 먼저 fulfilled 상태가 된 프로미스 처리 결과를 프로미스 형식으로 반환

45.6.4 Promise.allSettled

프로미스 배열을 인수로 받는 점에서 all이나 race와 같게 동작하지만, reject를 반환하는 프로미스가 있는 경우 진행을 멈추는 것이 아니라 모든 프로미스가 settled 상태가 될 때까지 기다린 뒤, 모든 프로미스의 결과값을 반환

45.7 마이크로태스크 큐

setTimeout(() => console.log(1), 0);

Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3))

프로미스의 후속처리 메서드의 콜백함수는 태스크 큐가 아니라 마이크로태스크 큐에 저장
마이크로태스크 큐는 태스크 큐보다 우선 순위가 높아 마이크로태스트 큐에 있는 함수를 먼저 실행 후, 마이크로태스트 큐가 비면 태스크 큐에 있던 함수를 가져와 실행

45.8 fetch

HTTP 요청 전송 기능을 제공하는 클라이언트 사이트 WebAPI.

const promise = fetch(url, [, option])

HTTP 응답을 나타내는 Response 객체를 래핑한 Promise 객체를 반환
반환된 HTTP 응답 몸체를 위한 다양한 메서드를 제공

const wrongUrl = 'url'

fetch(wrongUrl)
.then(() => console.log('ok'))
.catch(() => console.log('error')); // ok

http 에러의 경우 reject로 취급되지 않고, ok의 값을 false로 체크한 resolve 결과를 가짐
네트워크 장애나 CORS 에러에 의한 요청이 완료되지 못한 경우에만 프로미스를 reject

const wrongUrl = 'url'

fetch(wrongUrl)
.then((response) => {
    if(!response.ok) throw new Error('error~');
    console.log('ok')
}
.catch(() => console.log('error')); // ok

axios는 모든 HTTP 에러를 reject하는 프로미스를 반환

profile
PRE-FE에서 PRO-FE로🚀🪐!

0개의 댓글