45장 프로미스

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

45.1.1 콜백 헬
// GET 요청을 위한 비동기 함수
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}')
        }
    } 
}
// id가 1인 post를 취득
get('https://jsonplaceholder.typicode.eom/posts/1');
/*
{
"userid": 1,
"id": 1,
"title": "sunt aut facere ... ",
"body": "quia et suscipit "
}
*/
// GET 요청을 위한 비동기 함수
const get = url => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.send();
    xhr.onload =()=>{
    if (xhr.status === 200) {
        // ① 서버의 응답을 반환한다.
        return JSON.parse(xhr.response);
    }
    console.error( ${xhr.status} ${xhr.statusText});
    }
}
// ② id가 1인 post를 취득
const response = get('https://jsonplaceholder.typicode.com/posts/1');
console.log(response); // undefined
// GET 요청을 위한 비동기 함수
const get = (url, successcallback, failurecallback) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.send();
    xhr.onload =()=>{
        if (xhr.status === 200) {
            // 서버의 응답을 콜백 함수에 인수로 전달하면서 호출하여 응답에 대한 후속 처리를 한다.
            successCallback(JSON.parse(xhr.response));
        } else {
            // 에러 정보를 콜백 함수에 인수로 전달하면서 호출하여 에러 처리를 한다.
            failureCallback(xhr.status);
        }
    }
}
// id가 1인 post를 취득
// 서버의 응답에 대한 후속 처리를 위한 콜백 함수를 비동기 함수인 get에 전달해야 한다.
get('https://jsonplaceholder.typicode.eom/posts/l', console.log, console.error);
/*•
{
"userid": 1,
"id": 1,
"title": "sunt aut facere ... ",
"body": "quia et suscipit ... "
}
*/
// GET 요청을 위한 비동기 함수
const get = (url, callback) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.send();
    xhr.onload =()=>{
        if (xhr.status === 200) {
            // 서버의 응답을 콜백 함수에 전달하면서 호출하여 응답에 대한 후속 처리를 한다.
            callback(JSON.parse(xhr.response));
        } else {
            console.error( ${xhr.status} ${xhr.statusText} );
        }
    };
};
const url = 'https://jsonplaceholder.typicode.com';
// id가 1인 post의 userid를 취득
get('${url}/posts/l', ({ userid }) => {
    console.log(userid); // 1
    // post의 userid를 사용하여 user 정보를 취득
    get( ${url}/users/${userld} , userinfo => {
        console.log(userinfo); // {id: 1, name: "Leanne Graham", username: "Bret", ... }
    })
})
get('/stepl1', a => {
    get('/step2/${a}', b => {
        get('/step3/${b}', c => {
            get('/step4/${c}', d => {
                console.log(d);
            })
        }) 
    })
})
45.1.2 에러 처리의 한계
try {
    setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
    // 에러를 캐치하지 못한다
    console.error('캐치한 에러', e);
}

45.2 프로미스의 생성

// 프로미스 생성
const promise = new Promise((resolve, reject) => {
    // Promise 함수의 콜백 함수 내부에서 비동기 처리를 수행한다.
    if (/* 비동기 처리 성공 */) {
        resolve('result');
    } else { /* 비동기 처리 실패 */
        reject('failure reason');
    }
})
// GET 요청을 위한 비동기 함수
const promiseGet = url => {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.send();
        xhr.onload =()=>{
            if (xhr.status === 200) {
                // 성공적으로 응답을 전달받으면 resolve 함수를 호출한다.
                resolve(JSON.parse(xhr.response));
            } else {
                // 에러 처리를 위해 reject 함수를 호출한다.
                reject(new Error(xhr.status));
            }
        } 
    }) 
}
// promiseGet 함수는 프로미스를 반환한다.
promiseGet('https://jsonplaceholder.typicode.com/posts/!');

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

45.3.1 Promise.prototype.then

// fulfilled
new Promise(resolve => resolve('fulfilled'))
.then(v => console.log(v), e => console.error(e)); // fulfilled
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.then(v => console.log(v), e => console.error(e)); // Error: rejected

45.3.2 Promise.prototype.catch

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.catch(e => console.log(e)); // Error: rejected

45.3.3 Promise.prototype.finally

new Promise(() => {})
    .finally(() => console.log('finally')); // finally

45.4 프로미스의 에러 처리

const wrongUrl = 'https://jsonplaceholder.typicode.eom/XXX/l';
// 부적절한 URLOI 지정되었기 때문에 에러가 발생한다.
promiseGet(wrongUrl).then(
    res => console.log(res),
    err => console.error(err)
); // Error: 404
const wrongUrl = 'https://jsonplaceholder.typicode.eom/XXX/l';
// 부적절한 URLOI 지정되었기 때문에 에러가 발생한다.
promiseGet(wrongUrl)
.then(res => console.log(res))
.catch(err => console.error(err)); // Error: 404
promiseGet('https://jsonplaceholder.typicode.eom/todos/l').then(
    res => console.xxx(res),
    err => console.error(err)
); // 두 번째 콜백 함수는 첫 번째 콜백 함수에서 발생한 에러를 캐치하지 못한다.
promiseGet('https://jsonplaceholder.typicode.eom/todos/l')
    .then(res => console.xxx(res))
    .catch(err => console.error(err)); // TypeError: console.xxx is not a function

45.5 프로미스 체이닝

const url = 'https://jsonplaceholder.typicode.com'
// id가 1인 post의 userid를 취득
promiseGet('${url}/posts/l')
// 취득한 post의 userid로 user 정보를 취득
.then(({ userid }) => promiseGet('${url}/users/${userld}'))
    .then(userlnfo => console.log(userinfo))
        .catch(err => console.error(err));

45.6 프로미스의 정적 메서드

45.6.1 Promise.resolve / Promise.reject
// 배열을 resolve하는 프로미스를 생성
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [1, 2, 3]
const resolvedPromise = new Promise(resolve => resolve([1, 2, 3]));
resolvedPromise.then(console.log); // [1, 2, 3]
// 에러 객처/를 reject하는 프로미스를 생성
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!
const rejectedPromise = new Promise((_, reject) => reject(new Error( 'Error!')));
rejectedPromise.catch(console.log); // Error: Error!
45.6.2 Promise.all
const requestDatal = () =>
new Promise(resolve => setTimeout(() => resolve(l), 3000));
const requestData2 = () =>
new Promise(resolve => setTimeout(() => resolve(2), 2000));
const requestData3 = () =>
new Promise(resolve => setTimeout(() => resolve(3), 1000));
// 세 개의 비동기 처리를 순차적으로 처리
const res = [];
requestData1()
    .then(data => {
        res.push(data);
        return requestData2();
    })
    .then(data => {
        res.push(data);
        return requestData3();
    })
    .then(data => {
        res.push(data);
        console.log(res); // [1, 2, 3] = 약 6초 소요
    })
    .catch(console.error);
const requestDatal = () =>
    new Promise(resolve => setTimeout(() => resolve(l), 3000));
const requestData2 = () =>
    new Promise(resolve => setTimeout(() => resolve(2), 2000));
const requestData3 = () =>
    new Promise(resolve => setTimeout(() => resolve(3), 1000));
// 세 개의 비동기 처리를 병렬로 처리
Promise.all([requestData1(), requestData2(), requestData3()])
.then(console.log) // [ 1, 2, 3 ] = 약 3초 소요
.catch(console.error);
45.6.3 Promise.race
Promise.race([
new Promise(resolve => setTimeout(() => resolve(l), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
])
.then(console.log) // 3
.catch(console.log);
45.6.4 Promise.allSettled
Promise.allSettled([
new Promise(resolve => setTimeout(() => resolve(l), 2000)),
new Promise((_, reject) => setTimeout(() => reject(new Error('Error!')), 1000))
]).then(console.log);
/*
[
{status: "fulfilled", value: 1},
{status: "rejected", reason: Error: Error! at <anonymous>:3:54}
J
*/

45.7 마이크로태스크 큐

setTimeout(() => console.log(l), 0);
Promise.resolve()
    .then(() => console.log(2))
    .then(() => console.log(3));

45.8 fetch

const promise = fetch(url [, options])
fetch('https://jsonplaceholder.typicode.eom/todos/l')
// response는 HTTP 응답을 나타내는 Response 객체다.
// json 메서드를 사용하여 Response 객체에서 HTTP 응답 몸체를 취득하여 역직렬화한다.
.then(response => response.json())
// json은 역직렬화된 HTTP 응답 몸체다.
.then(json => console.log(json));
// {userid: 1. id: 1, title: "delectus aut autem", completed: false}
// 부적절한 URL이 지정되었기 때문에 404 Not Found 에러가 발생한다.
fetch(wrongllrl)
// response는 HTTP 응답을 나타내는 Response 객체다.
    .then(response = {
        if (Iresponse.ok) throw new Error(response.statusText);
        return response.json()
    })
        .then(todo = console.log(todo))
        .catch(err = console.error(err));

끝!