ABOUT ME

GoGo!

Today
Yesterday
Total
  • [ES6] Promise에 대하여
    ■ Front-End/- JavaScript & TypeScript 2019. 6. 19. 18:21

    Promise란?

    ES6에서 비동기 처리를 위한 패턴.

    전통적인 콜백 패턴이 가진 단점을 보완하고, 비동기 처리 시점을 명확하게 표현한다.

     

    아래 코드는 전통적인 콜백 패턴이 가진 단점을 보여준다.

    step1(function(value1) {
    step2(value1, function(value2) {
    step3(value2, function(value3) {
    step4(value3, function(value4) {
    step5(value4, function(value5) {
    // value5를 사용하는 처리
    });
    });
    });
    });
    });
    try {
    setTimeout(() => { throw 'Error!'; }, 1000);
    } catch (e) {
    console.log('에러를 캐치하지 못한다..');
    console.log(e);
    }
    view raw test.js hosted with ❤ by GitHub

     

    위 코드를 개선하기 위해 Promise를 사용한다.

     

    Promise의 생성

    // Promise 객체의 생성
    const promise = new Promise((resolve, reject) => {
    // 비동기 작업을 수행한다.
    if (/* 비동기 작업 수행 성공 */) {
    resolve('result'); // 후속 처리 메서드로 이동
    }
    else { /* 비동기 작업 수행 실패 */
    reject('failure reason'); // 후속 처리 메서드로 이동
    }
    });
    view raw promise_ex1.js hosted with ❤ by GitHub

     

    Promise의 후속 처리 메서드

    1. then

    then 메소드는 두 개의 콜백 함수를 인자로 전달 받는다. 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출되고 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다.

     

    2. catch

    예외(비동기 처리에서 발생한 에러와 then 메소드에서 발생한 에러)가 발생하면 호출된다. 따라서 에러 처리는 catch 메서드를 사용하는 것이 더 효율적이다.

     

    예제 코드

    <!DOCTYPE html>
    <html>
    <head>
    <title>Promise example</title>
    </head>
    <body>
    <h1>Promise example</h1>
    <pre id="result"></pre>
    <script>
    // 비동기 함수
    function get(url) {
    // Promise 객체의 생성과 반환
    return new Promise((resolve, reject) => {
    // XMLHttpRequest 객체 생성
    const xhr = new XMLHttpRequest();
    // 서버 응답 시 호출될 이벤트 핸들러
    xhr.onreadystatechange = function () {
    // 서버 응답 완료
    if (xhr.readyState === XMLHttpRequest.DONE) {
    if (xhr.status === 200) { // 정상 응답
    // resolve 메소드에 처리 결과를 전달
    resolve(xhr.response);
    } else { // 비정상 응답
    // reject 메소드에 에러 메시지를 전달
    reject('Error: ' + xhr.status);
    }
    }
    };
    // 비동기 방식으로 Request를 오픈한다
    xhr.open('GET', url);
    // Request를 전송한다
    xhr.send();
    });
    }
    const url = 'http://jsonplaceholder.typicode.com/post/1';
    /*
    비동기 함수 get은 Promise 객체를 반환한다.
    Promise 객체의 후속 메소드를 사용하여 비동기 처리 결과에 대한 후속 처리를 수행한다.
    */
    get(url).then(
    // 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출된다.
    result => document.getElementById('result').innerHTML = result,
    // 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다.
    error => console.log(error)
    );
    </script>
    </body>
    </html>

     

    Promise Chaining이란?

    비동기 함수의 처리 결과를 가지고 다른 비동기 함수를 호출해야 하는 경우, 함수의 호출이 중첩(nesting)이 되어 복잡도가 높아지는 콜백 헬이 발생한다. 프로미스는 후속 처리 메소드를 체이닝(chainning)하여 여러 개의 프로미스를 연결하여 사용할 수 있다. 이로써 콜백 헬을 해결한다.

     

    Promise 정적 메서드

    (1) Promise.resolve

    인자로 전달된 값을 resolve하는 Promise를 생성한다.

     

    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 ]
    view raw promise_ex2.js hosted with ❤ by GitHub

     

    (2) Promise.reject 

    Promise.reject 메소드는 인자로 전달된 값을 reject하는 프라미스를 생성한다.

     

    const rejectedPromise = Promise.reject(new Error('Error!'));
    rejectedPromise.catch(console.log); // Error: Error!
    // 위 예제는 아래 예제와 동일하게 동작한다.
    const rejectedPromise = new Promise((resolve, reject) => reject(new Error('Error!')));
    rejectedPromise.catch(console.log); // Error: Error!
    view raw promise_ex3.js hosted with ❤ by GitHub

     

    (3) Promise.all

    프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달 받는다. 그리고 전달받은 모든 프로미스를 병렬로 처리하고 그 처리 결과를 resolve하는 새로운 프로미스를 반환한다. 

    모든 프라미스의 처리가 종료될 때까지 기다린 후 아래와 모든 처리 결과를 resolve 또는 reject한다. 모든 프로미스의 처리가 성공하면 각각의 프로미스가 resolve한 처리 결과를 배열에 담아 resolve하는 새로운 프로미스를 반환한다. 이때 첫번째 프로미스가 가장 나중에 처리되어도 Promise.all 메소드가 반환하는 프로미스는 첫번째 프로미스가 resolve한 처리 결과부터 차례대로 배열에 담아 그 배열을 resolve하는 새로운 프로미스를 반환한다. 즉, 처리 순서가 보장된다.

     

    Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
    new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
    new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
    ]).then(console.log) // [ 1, 2, 3 ]
    .catch(console.log);
    view raw promise_ex4.js hosted with ❤ by GitHub

    첫번째 프로미스는 3초 후에 1을 resolve하여 처리 결과를 반환한다.

    두번째 프로미스는 2초 후에 2을 resolve하여 처리 결과를 반환한다.

    세번째 프로미스는 1초 후에 3을 resolve하여 처리 결과를 반환한다.

     

    프로미스의 처리가 하나라도 실패하면 가장 먼저 실패한 프로미스가 reject한 에러를 reject하는 새로운 프로미스를 즉시 반환한다.

     

    Promise.all([
    new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 1!')), 3000)),
    new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 2!')), 2000)),
    new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 3!')), 1000))
    ]).then(console.log)
    .catch(console.log); // Error: Error 3!
    view raw promise_ex5.js hosted with ❤ by GitHub

    위 예제의 경우, 세번째 프로미스가 가장 먼저 실패하므로 세번째 프로미스가 reject한 에러가 catch 메소드로 전달된다.

     

     

    (4) Promise.race()

    Promise.race 메소드는 Promise.all 메소드와 동일하게 프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달 받는다. 그리고 Promise.race 메소드는 Promise.all 메소드처럼 모든 프라미스를 병렬 처리하는 것이 아니라 가장 먼저 처리된 프라미스가 resolve한 처리 결과를 resolve하는 새로운 프라미스를 반환한다.

     

    Promise.race([
    new Promise(resolve => setTimeout(() => resolve(1), 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);
    view raw promise_ex6.js hosted with ❤ by GitHub

     

     

    참고 사이트

    https://poiemaweb.com/es6-promise

     

    Promise | PoiemaWeb

    Promise는 비동기 처리가 성공(fulfilled)하였는지 또는 실패(rejected)하였는지 등의 상태(state) 정보를 갖는다. Promise는 Promise 생성자를 통해 인스턴스화한다. Promise 생성자는 비동기 작업을 수행할 콜백함수를 인자로 전달받는데 이 콜백함수는 resolve와 reject 콜백함수를 인수로 전달받는다.

    poiemaweb.com

     

     

Designed by Tistory.