자바스크립트 Promise 와 Async & Await 얕게 살펴보기

Harimad·2022년 8월 12일
0

js

목록 보기
6/14
post-thumbnail

들어가며

  • 비동기 코드를 작성하다 보면 아래의 예시 코드 처럼 중첩 콜백 함수를 매개변수로 사용하는 경우가 생깁니다.
  • 아래의 예시가 바로 콜백 지옥(Callback Hell)이라고 부릅니다.
  • 이런 코드는 코드의 들여쓰기가 점점 깊어져서 이해하기 힘들어 결국 유지 보수하기가 힘들어 집니다.
timer(1000, function() {
    console.log('Tastk1');
    timer(1000, function() {
        console.log('Task2');
        timer(1000, function() {
            console.log('Task3');
            timer(1000, function() {
                console.log('Task4');
                timer(1000, function() {
                    console.log('Task5');
                })
            })
        })
    })
})
  • 아래 처럼 Promise 객체를 then()메서드로 처리한다면 정돈된 코드를 사용할 수 있습니다.
timer(1000)
    .then(function() {
        console.log('Tastk1');
        return timer(1000);
    })
    .then(function() {
        console.log('Tastk2');
        return timer(1000);
    })
    .then(function() {
        console.log('Tastk3');
        return timer(1000);
    })
  • ES6에서 새로 도입된 Promise 객체를 이용하면 비동기 처리를 더욱 명확하게 할 수 있습니다.
  • Promise는 비동기 작업이 끝나면 결과값으로 성공 혹은 실패를 처리 할 수 있습니다.

Promise

  • Promise 생성자 함수를 이용해서 인스턴스화 합니다. 그리고 비동기 작업이 성공적으로 실행하면 resolve() 함수가 호출되고, 실패하면 에러 객체와 함께 reject() 함수를 호출합니다.

  • resolve()나 reject() 함수 중에 반드시 하나는 호출됩니다.

  • Promise 객체는 상태를 나타내는 state 프로퍼티가 있습니다. 총 3가지 상태가 있습니다.
    ① fullfilled : 성공적인 작업 종료
    ② rejected : 작업 실패
    ③ pending : 작업 실패도 이행도아닌 초기 단계

  • Promsie 객체는 then(), catch(), finally() 메서드를 통해서 사용할 수 있습니다.

  • then() 메서드는 Promise 객체를 리턴합니다.

  • then() 메서드는 2개의 콜백 함수를 인자로 받습니다.

  • 첫 번째 인자는 fullfilled되었을 때의 결과를 다루고, 두 번째 인자는 reject되었을 때 에러를 다루는 콜백 함수입니다.

const promise = new Promise((resolve, reject) {
    // 코드
})

promise.then(
    result => {
        // result를 다루는 콜백함수
    },
    error => {
        // error를 다루는 콜백함수
    }
)

// 결과만 다루는 콜백
promise.then(result => {
	// 코드
}
            
// 에러만 다루는 콜백 1
promise.then(null, error => {
	// 코드             
})

// 에러만 다루는 콜백 2
promise.catch(error => {
	// 코드
})
              
// fullfilled, rejected와 상관없이 실행되는 finally() 메서드
promise.finally(() => {
	// 코드
})
  • fetch() 메서드는 promise 객체를 리턴합니다.
  • fetch() 리턴 자리에 then()를 붙여서 값을 확인해보면 response object가 출력됩니다.
fetch('https://jsonplaceholder.typicode.com/posts')
    .then(function (response) {
        console.log(response); //response object 출력
    })
  • response 값을 json으로 변환하고
    두 번째 then에서 json값을 출력해 봅니다.
fetch('https://jsonplaceholder.typicode.com/posts')
    .then(function (response) {
        return response.json();
    })
    .then(function (myJson) {
        console.log(myJson); //100개의 객체 값. (100) {{...}, {...} ...}
        console.log(myJson[0]); //object 이다. {userId: 1, id: 1, title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', body: 'quia et suscipit\nsuscipit recusandae consequuntur …strum rerum est autem sunt rem eveniet architecto'}
        console.log(JSON.stringify(myJson[0])); //string 이다. VM1036 practice:8 {"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
    });

async & await

  • promise를 사용하고 있는 비동기 함수를 동기 함수처럼 사용할 수 있게 해주는 async 와 await 키워드가 있습니다.
  • async 키워드는 함수 앞에 붙입니다. 함수 앞에 async 를 붙이면 Promise를 반환하게 됩니다.
  • await는 async 함수 내에서만 사용할 수 있습니다.
  • Promise 객체를 then() 메서드로만 쓴다면 원하는 출력 결과를 얻지 못할 수 있습니다. promise는 비동기 함수 이기 때문 입니다.
  • 아래의 예시를 보면 start와 end가 먼저 출력됩니다. 원하지 않는 상황이죠.
function timer(time) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(time);
        }, time);
    });
}

console.log('start');

timer(1000).then(function (time) {
    console.log('time: ' + time); //time: 1000
    return timer(time + 1000);
}).then(function (time) {
    console.log('time: ' + time); //time: 2000
    return timer(time + 1000);
}).then(function (time) {
    console.log('time: ' + time); //time: 3000
});

console.log('end');

/* 실행결과
** 
** start
** end
** time: 1000
** time: 2000
** time: 3000
*/
  • async & await를 이용하면 동기적인 코드 인것처럼 start --> time출력들 -> end 이렇게 출력되도록 만들 수 있습니다.
function timer(time) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(time);
        }, time);
    });
}

async function run() {
    console.log('start');
    var time = await timer(1000);
    console.log('time: ' + time);
    time = await timer(time + 1000);
    console.log('time: ' + time);
    time = await timer(time + 1000);
    console.log('time: ' + time);
    console.log('end');
}
run();

/* 실행결과
** 
** start
** time: 1000
** time: 2000
** time: 3000
** end
*/
  • fetch()로 서버로 부터 데이터를 받는 방식을 asycn&await를 적용시켜 보겠습니다.
function getData() {
    fetch('https://jsonplaceholder.typicode.com/posts')
        .then(res =>res.json())
        .then(data => {
            console.log(data);
        })
}

async function getDataWithAsync() {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts')
    const json = await res.json();
    console.log(json);
}

getData(); // (100) [{…}, {…}, {…}, {…}, {…}, {…}, {…} ...]
getDataWithAsync(); // (100) [{…}, {…}, {…}, {…}, {…}, {…}, {…} ...]

나가며

지금까지 비동기 코드를 여러번 작성하는 것보다 Promise 객체를 then() 메서드로 정리된 코드를 살펴봤습니다.
Promise 객체와 then() 메서드를 쓰는 것보다 간편하게 사용할 수 있는 async/await 키워드도 살펴봤습니다.
async/await 키워드를 사용하면 비동기 함수를 동기 함수처럼 사용할 수 있게됩니다.
이 키워드는 비교적 최근에 나왔기 때문에 익숙하지 않을 수 있습니다.
아래의 참고 링크에 나와있는 글 들을 참고하여 더욱 깊은 Promise/async&await 키워드를 이해하시길 바랍니다.


참고

profile
Here and Now. 🧗‍♂️

0개의 댓글