Javascript Callback 패턴

shelly·2022년 4월 23일

비동기함수란?

비동기함수란, 비동기로 동작하는 코드를 포함한 함수를 뜻한다.

예를들면, setTimeout, setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.
따라서 이 함수들은 비동기 함수이며, 이를 포함한 함수 또한 비동기 함수라고 한다.

비동기함수를 사용할 때 주의할 점

아래와 같은 API호출 코드가 있다.

비동기함수의 결과값은 외부에 반환할 수 없으며, 상위 변수에 할당할 수 없다.

const getId = (url) => {
  let id
  const xhr = new XHMHttpRequest()
  xhr.open('GET', url)
  xhr.onload = () => {
    if (xhr.status === 200) { 
      id = xhr.response.id
    } else {
      console.error('ERROR') 
    }
  }
  
  return id
}

const id = getId('https://somethingurl.com')
console.log(id) // undefined

위의 코드의 의도는 api로 부터 response받은 id를 console.log로 출력하는 것이었다.
하지만, 마지막줄 console.log(id)의 결과값은 undefined이다.
왜 그럴까?

xhr.onload = () => {
  /** 내부 코드 **/
  if (xhr.status === 200) { 
    id = xhr.response.id
  } else {
    console.error('ERROR') 
  }
}

xhr.onload는 앞서 설정한 옵션대로 HTTP 요청을 보낸다. HTTP요청에 대한 응답이 돌아오면 내부 코드를 실행한다.
즉, 비동기 처리 방식으로 동작한다.
즉, getId 함수는 비동기 함수이다.
즉, getId 함수는 HTTP요청의 응답에 대한 결과(내부코드)를 처리하기 전에, 종료된다.

코드와 함께 아래의 (순서)를 살펴보자.

const getId = (url) => {
  let id
  const xhr = new XHMHttpRequest()
  xhr.open('GET', url)
  
  // (1) HTTP 요청을 보낸다.
  xhr.onload = () => {
    // (4) 응답에 대한 결과를 처리한다.
    if (xhr.status === 200) { 
      // (5) 변수에 결과값 id를 할당한다. 하지만, 이미 getId 함수는 종료된 이후이기 때문에, 아무런 영향을 미치지 못한다.
      id = xhr.response.id
    } else {
      console.error('ERROR') 
    }
  }
  
  // (2) 값이 지정되어있지 않기 때문에 undefined를 return한다.
  return id
}

const id = getId('https://somethingurl.com')

// (3) undefined 를 출력한다.
console.log(id) // undefined

비동기 함수의 결과에 따른 처리를 하기 위해서 Callback 패턴을 사용한다.

비동기 방식으로 동작하는 함수는 비동기 함수 내부에서 처리를 해야한다.
이러한 처리를 돕기 위해 Callback 패턴을 사용한다.

// callback 패턴 사용 예시
const getId = (url, successCallback, failureCallback) => {
  const xhr = new XHMHttpRequest()
  xhr.open('GET', url)
  
  // (2) HTTP 요청을 보낸다.
  xhr.onload = () => {
    
    // (3) 성공했을 경우, successCallback인 console.log 함수를 실행하고, 
    // 실패했을 경우, failureCallback인 console.error 함수를 실행한다. 
    if (xhr.status === 200) { 
      successCallback(xhr.response.id) // id 출력
    } else {
      failureCallback('ERROR') // 'ERROR'출력
    }
  }
}

// (1) url과 callback 함수를 파라미터로 넘겨준다.
getId('https://somethingurl.com', console.log, console.error)

0개의 댓글