비동기 작업과 콜백함수

로선생·2021년 10월 9일
0

외부 API활용

목록 보기
1/6

API 제공:
https://newsapi.org/

비동기 작업?

웹 애플리케이션 제작시 시간이 걸리는 작업이 있다.
서버 쪽 데이터가 필요하다면 Ajax기법을 사용해 서버의 API를 호출해 데이터를 수신한다.
해당 작업시 시간이 걸려 즉시 처리되지 않고 응답을 받을 때까지 기다렸다가, 전달받은 응답 데이터를 처리한다. 해당 작업은 비동기적으로 처리하게 된다.
동기적으로 처리하면 요청이 끝날 때까지 중지 상태가 되기 때문에 다른 작업을 할 수 없다.
하지만 비동기적으로 처리하면 웹 애플리케이션이 멈추지 않고 기다리는 과정에서 다른 요청을 처리할 수 있게 된다.

서버 API를 호출할 때 이외에도 비동기적으로 작업을 처리하는 예제로는 setTimeout함수를 사용하여 특정 작업을 예약할 때이다.

function printMe() {
console.log('Hello World!');
}
setTimeout(printMe, 3000);
console.log('대기 중...'); 

해당 작업은 3초 동안 코드를 멈추는 것이 아니라, 일단 위에서 아래까지 다 호출되가 3초 뒤에 printMe가 호출된다.

자바스크립트에서 비동기 작업시 흔히 콜백 함수를 사용한다.
위의 작업에서 printMe가 3초 뒤에 호출되도록 printMe함수 자체를 setTimeout함수의 인자로 전달해 주었는데, 이런 함수를 콜백 함수라고 부른다.

콜백함수

다른 코드를 확인해보자. 파라미터 값이 주어지면 1초 뒤에 10을 더해서 반환하는 함수가 있다고 하자.
해당 함수가 처리된 직후 어떤 작업을 하고 싶다면 콜백함수를 활용해서 작업한다.

function increase(number, callback) {
setTimeout(() => {
    const result = number + 10;
  if (callback) {
    callback(result);
  }
}, 1000)
}


increase(0, result => {
  console.log(result);
});

콜백 지옥

1초에 걸쳐서 여러번 순차적으로 처리하고 싶다면 콜백 함수를 중첩하여 구현할 수 있다.

function increase(number, callback) {
setTimeout(() => {
  const result = number + 10;
  if (callback) {
    callback(result);
  }
}, 1000);
}
 
console.log('작업 시작');
increase(0, result => {
console.log(result);
increase(result, result => {
  console.log(result);
  increase(result, result => {
    console.log(result);
    increase(result, result => {
      console.log(result);
      console.log('작업 완료');
    });
  });
});
});

이 가독성이 나쁜 형태를 콜백 지옥이라고 한다. (지양해야 한다)

Promise

이를 방지하기 위해 es6에서 promise를 도입하였다.

function increase(number) {
const promise = new Promise((resolve, reject) => {
  // resolve는 성공, reject는 실패
  setTimeout(() => {
    const result = number + 10;
    if (result > 50) {
      // 50보다 높으면 에러 발생시키기
      const e = new Error('NumberTooBig');
      return reject(e);
    }
    resolve(result); // number 값에 +10 후 성공 처리
  }, 1000);
});
return promise;
}
 
increase(0)
.then(number => {
  // Promise에서 resolve된 값은 .then을 통해 받아 올 수 있음
  console.log(number);
  return increase(number); // Promise를 리턴하면
})
.then(number => {
  // 또 .then으로 처리 가능
  console.log(number);
  return increase(number);
})
.then(number => {
  console.log(number);
  return increase(number);
})
.then(number => {
  console.log(number);
  return increase(number);
})
.then(number => {
  console.log(number);
  return increase(number);
})
.catch(e => {
  // 도중에 에러가 발생한다면 .catch를 통해 알 수 있음
  console.log(e);
});

여러 작업을 연달아 처리한다고 해서 함수를 여러 번 감싸는 것이 아니라 .then을 사용하여 그다음 작업을 설정하기 때문에 콜백 지옥이 형성되지 않는다.

async/await

async/await는 Promise를 더욱 쉽게 사용할 수 있도록 해 주는 ES2017(ES8) 문법이다.

이 문법을 사용하려면 함수의 앞부분에 async 키워드를 추가하고, 해당 함수 내부에서 Promise의 앞부분에 await 키워드를 사용한다. 이렇게 하면 Promise가 끝날 때까지 기다리고, 결과 값을 특정 변수에 담을 수 있다.

function increase(number) {
const promise = new Promise((resolve, reject) => {
  // resolve는 성공, reject는 실패
  setTimeout(() => {
    const result = number + 10;
    if (result > 50) { // 50보다 높으면 에러 발생시키기
      const e = new Error(‘NumberTooBig‘);
              return reject(e);
    }
          resolve(result); // number 값에 +10 후 성공 처리
  }, 1000)
});
return promise;
}


async function runTasks() {
try { // try/catch 구문을 사용하여 에러를 처리합니다.
  let result = await increment(0);
  console.log(result);
  result = await increment(result);
  console.log(result);
  result = await increment(result);
  console.log(result);
  result = await increment(result);
  console.log(result);
  result = await increment(result);
  console.log(result);
  result = await increment(result);
  console.log(result);
} catch (e) {
  console.log(e);
}
}
profile
이제는 이것저것 먹어요

0개의 댓글