[JavaScript] 비동기 처리와 Promise

정예원·2021년 8월 19일
0

JavaScript

목록 보기
5/13
post-thumbnail

Promise를 소개하기 전, ES6 이전 비동기 처리에 사용하던 콜백 패턴에 대해 알아보자.

1. 비동기 처리


특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고
다음 코드를 먼저 실행하는 자바스크립트의 특성이다.

비동기 처리 예시 3가지

1. addEventListener 함수

두번째 인자로 넘겨진 함수는 바로 실행되지 않고, 이벤트 리스너가 정의한 이벤트가 발행할 때 실행된다.

function onButtonClick() {
    alert('click!')
}

document.querySelector('.button1').addEventListener('click', onButtonClick)

2. setTimeout과 setInterval

첫 번째 인자로 넘겨진 함수는 바로 실행되지 않고, setTimeout 혹은 setTimeout의 시간만큼 지난 후에 실행된다.

function work() {
    console.log('work!')
}

setTimeout(work, 1000)
setInterval(work, 3000)

console.log('work process')

work process가 출력된 후 1초 후 work!이 출력되고
이 후 3초마다 work!이 출력된다.

3. XMLHttpRequest(XHR)

데이터를 비동기로 요청하고, 요청 후의 동작을 비동기로 처리한다.

XHR의 예시는 아래 프로미스와 콜백을 비교하며 설명하겠다.

2. 콜백 패턴


자바스크립트에서 비동기 처리를 위한 하나의 패턴은 콜백 함수를 사용하는 것이다.

콜백 패턴의 단점 : 콜백 헬

처리 순서를 보장하기 위해 여러 개의 콜백 함수가 네스팅(nesting, 중첩)되어 복잡도가 높아지는 것을 콜백 헬이라고 부른다.
비동기 처리 모델은 실행 완료를 기다리지 않고 즉시 다음 task를 실행한다.
따라서 비동기 함수 내에서 처리 결과를 반환하면 기대한 대로 동작하지 않는다.

  • 가독성이 나쁘다.
  • 처리 중 발생한 에러의 처리가 곤란하다.
  • 여러 개의 비동기 처리를 한번에 처리하는 것이 어렵다.
step1(function(value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3) {
      step4(value3, function(value4) {
        step5(value4, function(value5) {
            // value5를 사용하는 처리
        });
      });
    });
  });
});

3. 프로미스의 등장


프로미스는 Promise 생성자 함수를 통해 인스턴스화한다.
Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달받는데 이 콜백 함수는 resolvereject 함수를 인자로 전달받는다.

// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행한다.

  if (/* 비동기 작업 수행 성공 */) {
    resolve('result');
  }
  else { /* 비동기 작업 수행 실패 */
    reject('failure reason');
  }
});

4. 콜백 패턴을 프로미스로 변환하는 예제


콜백 패턴

export function request(url, successCallback, failCallback) {
    const xhr = new XMLHttpRequest()
    xhr.addEventListener('load', (e) => {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                successCallback(JSON.parse(xhr.responseText))
            } else {
                failCallback(xhr.statusText)
            }
        }
    })
    xhr.addEventListener('error', (e) => failCallback(xhr.statusText))

    xhr.open('GET', url)
    xhr.send()
}

프로미스

export function request(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.addEventListener('load', (e) => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve(JSON.parse(xhr.responseText))
                } else {
                    reject(xhr.statusText)
                }
            }
        })
        xhr.addEventListener('error', (e) => reject(xhr.statusText))

        xhr.open('GET', url)
        xhr.send()
    })
}

프로미스 코드를 살펴보면 Promise 생성자 함수는 resolvereject를 인자로 받아
비동기 작업에 성공하면 처리 결과를 전달하고
비동기 작업에 실패하면 reject 메소드를 호출한다.

Promise의 장점

  1. callback hell에서 벗어날 수 있다.
  2. Promise로 정의된 작업끼리 연결할 수 있다.
  3. 코드의 depth가 크게 증가하지 않는다.

Reference

https://poiemaweb.com/es6-promise

profile
hello world!

0개의 댓글