본문 바로가기

프론트엔드/Vue.js

비동기 - 콜백과 프로미스 객체의 이해, 예외 처리

비동기 - 콜백과 프로미스 객체의 이해

function a() {
  console.log('A')
}
function b() {
  console.log('B')
}
a()
b()

위처럼 코드 작성 순서대로 출력된 방식이 동기 방식(Synchronous)라고 부릅니다.

 

function a() {
  setTimeout( () => {
    console.log('A')
  }, 1000)
}
function b() {
  console.log('B')
}
a()
b()

위처럼 a함수에 setTimeout함수를 사용해, 결국 B를 먼저 출력하고 A가 출력됩니다.

 

function a(callback) {
  setTimeout( () => {
    console.log('A')
    callback()
  }, 1000)
}
function b() {
  console.log('B')
}
a(function() {
  b()
})

함수와 상관없이 무조건 먼저 작성한 a함수를 실행한 후 b함수를 실행을 보장해줄 수 있는 콜백을 사용할 수 있습니다.

a함수에 setTimeout을 사용해도 불구하고 먼저 A를 출력한 후 callback()을 실행해 B를 출력합니다.

 

어떤 함수의 로직이 끝나고 다음 함수 실행을 callback함수로 보장했습니다.

 

function a(callback) {
  setTimeout( () => {
    console.log('A')
    callback()
  }, 1000)
}
function b(callback) {
  setTimeout( () => {
    console.log('B')
    callback()
  }, 1000)
}
function c(callback) {
  setTimeout( () => {
    console.log('C')
    callback()
  }, 1000)
}
a(function() {
  b(function() {
    c(function() {
      console.log('Done!')
    })
  })
})

위에 예시 보시면 콜백함수들이 너무 많으면 a, b, c함수 실행 시 점점 파고 들어가는 구조가 콜백지옥입니다.

지금은 3개만 있어서 잘 구분할 수 있지만 많아지면 이런 방식으로 관리하기 매우 불편할 수 있습니다.

이럴 때는 promise 객체를 사용할 수 있습니다.

 

function a() {
  // promise: 약속의 객체
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('A')
      resolve()
    }, 1000)
  })
}
function b() {
  console.log('B')
}
async function test() {
  await a()
  b()
}
test()

위에는 promise객체를 사용한 예시입니다.

a함수가 실행되면 같은 로직을 Promise 객체에 담고 반환됩니다. 

async과 await 키워드를 사용해서 a함수가 실행 끝나고 b함수를 실행할 수 있습니다.

 

function a() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('A')
    }, 1000)
  })
}
function b() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('B')
    }, 1000)
  })
}
function c() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('C')
    }, 1000)
  })
}

async function test() {
  await a()
  await b()
  await c()
  console.log('Done!')
}
test()

방금 콜백지옥을 위에 async, await를 통해 관리하기 편한 방식으로 동작할 수 있습니다.

 

비동기 - 예외 처리(then, catch, finally)

promise 객체는 ES6에서 나오는 개념이지만, async과 await는 ES8에서 나왔습니다.

async과 await로 처리할 수 없을 때는 예외 처리를 통해 작동해야 됩니다.

function a() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('A')
    }, 1000)
  })
}
function test() {
  // const promise = a()
  // promise.then(() => {
  //   console.log('B')
  // })
  a().then(() => {
    console.log('B')
  })
}
test()

a함수를 promise변수에 담고, promise.then()메소드를 통해 다음을 실행해줍니다.

a가 실행하는 곳에서 promise변수가 반환됨으로 굳이 promise변수 사용 안 해도 됩니다.

a().then()로 바로 표현해도 됩니다.

 

function a() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('A')
    }, 1000)
  })
}
function b() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('B')
    }, 1000)
  })
}
function c() {
  return new Promise(function (resolve) {
    setTimeout(() => {
      console.log('C')
    }, 1000)
  })
}
function test() {
  a().then(() => {
    return b()
  }).then(() => {
    return c()
  }).then(() => {
    console.log('Done!')
  })
  test()
}

여러개의 콜백을 사용하면 위에 체이닝방식으로 작성하면 됩니다.

 

function a(number) {
  return new Promise(function (resolve, reject) {
    if (number > 5) {
      reject()
      return
    }
    setTimeout(() => {
      console.log('A')
    }, 1000)
  })
}
function test() {
  a(7)
    .then(() => {
      console.log('Resolve!')
    })
    .catch(() => {
      console.log('Reject!')
    })
}
test()

위처럼 a함수에 number변수를 들어갈 때 조건문을 실행됩니다.

5보다 크면 reject합니다.

then()는 함수가 잘 처리 됐을 때 실행된 내용, catch()는 함수가 거부했을 때 처리된 내용을 출력합니다.

 

function a(number) {
  return new Promise(function (resolve, reject) {
    if (number > 5) {
      reject()
      return
    }
    setTimeout(() => {
      console.log('A')
    }, 1000)
  })
}
function test() {
  a(7)
    .then(() => {
      console.log('Resolve!')
    })
    .catch(() => {
      console.log('Reject!')
    })
    .finally(() => {
      console.log('Done!')
    })
}
test()

finally()메소드는 앞에 then()이 실행되던 catch() 실행되던 마지막으로 실행하는 로직을 구성해줍니다.

 

async function test() {
  try {
    await a(8)
    console.log('Resolve!')
  } catch(error) {
    console.log('Reject!')
  } finally {
    console.log('Done!')
  }
}
test()

async와 await키워드 사용할 때 try, catch, finally는 위와 같이 작성하면 됩니다.

여기서 try는 방금 then과 같은 역할을 하고 있다는 것을 보면 됩니다.

'프론트엔드 > Vue.js' 카테고리의 다른 글

Vue Router 정리  (0) 2023.08.31
Vuex Helpers, 핵심 정리  (0) 2023.08.31
컴포지션 API  (0) 2023.08.23
Vue문법(3) - 컴포넌트  (0) 2023.08.23
Vue문법(2) - 바인딩, 렌더링, 핸들링  (0) 2023.08.23