Posts callback과 promise 그리고 async/await
Post
Cancel

callback과 promise 그리고 async/await

1. callback 함수


콜백 함수는 나중에 호출할 함수를 의미하며 비동기 동작을 처리하기 위해 쓰인다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;
  script.onload = () => callback(script);
  script.onerroror = () =>
    callback(new Erroror(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
  document.body.append(script);
}

loadScript(
  'https://dapi.kakao.com/v2/maps/sdk.js?appkey=(API-KEY입력하기)',
  (script) => {
    console.log(`${script.src} load`);
    let script2 = document.createElement('script');
    script.src = 'map.js';
    document.body.append(script2);
  },
);

꼬리에 꼬리를 무는 비동기 동작이 많아지면 소위 ‘콜백 지옥(callback hell)’ 혹은 ‘멸망의 피라미드(pyramid of doom)’라고 불리는 중첩 문제가 발생한다.

2. Promise 객체


callback의 중첩 문제를 해결하기위해 나온 것이 Promise이다.

1
2
3
4
5
6
7
8
let promise = new Promise(function (resolve, reject) {
   try {
    ...비동기 작업
    resolve(value);//value가 then의 매개변수 result로 전달된다
  } catch (err) {
    reject(err);//err가 catch의 매개변수 error로 전달된다
  }
});

new Promise에 전달되는 함수는 executor(실행자, 실행 함수) 라고 부른다. executor는 new Promise가 만들어질 때 자동으로 실행되는 executor의 인수 resolvereject는 자바스크립트가 자체적으로 제공하는 콜백이다. executor는 resolve나 reject 중 하나를 반드시 호출해야 한다.

1
2
3
4
5
6
7
8
9
10
promise.then(
  function (result) {
    /* 결과(result)를 다룹니다 */
  },
  function (error) {
    /* 에러(erroror)를 다룹니다 */
  },
);

promise.catch(error);

.then은 프라미스에서 가장 중요하고 기본이 되는 메서드이다. Promise의 결과값을 받아온다. 에러가 발생한 경우만 다루고 싶다면 .then(null, function)같이 null을 첫 번째 인수로 전달하거나 .catch() 메서드를 사용한다. .catch(function)promise.then(null, function)과 동일하게 작동한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function loadScriptPromise(src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script');
    script.src = src;
    script.onload = () => resolve(script);
    script.onerror = () =>
      reject(new Error(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
    document.body.append(script);
  });
}

loadScriptPromise(
  'https://dapi.kakao.com/v2/maps/sdk.js?appkey=(API-KEY입력하기)',
)
  .catch((error) => console.log(`sdk load 중 ${error}가 발생하였습니다!`))
  .then(() => loadScriptPromise('map.js'))
  .catch((error) => console.log(`map.js를 load 중 ${error}가 발생하였습니다!`))
  .then(() => map())
  .catch((error) =>
    console.log(`map.js의 function map을 실행 중 ${error}가 발생하였습니다!`),
  );

.then 핸들러를 원하는 만큼 사용하다 마지막에 .catch 하나만 붙이면, .then 핸들러에서 발생한 모든 에러를 처리할 수 있다. 어디서 에러가 발생했는지 확인하고 싶다면 각각의 .then 핸들러 바로 뒤나 return하는 Promise 객체에 .catch를 붙인다.

3. async/await 문법

function 앞에 async를 붙이면 해당 함수는 반드시 프라미스를 반환하고, 프라미스가 아닌 것은 프라미스로 감싸 반환한다. 자바스크립트는 await 키워드를 만나면 프라미스가 처리(settled)될 때까지 기다린다. 결과는 그 이후 반환된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let loadScriptPromise = (src) => {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script');
    script.src = src;
    script.onload = () => resolve(script);
    script.onerror = () =>
      reject(new Error(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
    document.body.append(script);
  });
};

async function showMap(src) {
  try {
    await loadScriptPromise(src);
    return loadScriptPromise('map.js');
  } catch (error) {
    console.log(`${error}가 발생하였습니다!`);
  }
}
showMap('https://dapi.kakao.com/v2/maps/sdk.js?appkey=(API-KEY입력하기)');

await는 promise.then보다 좀 더 세련되게 프라미스의 result 값을 얻을 수 있도록 해주는 문법이다. promise.then보다 가독성 좋고 쓰기도 쉽다. await가 던진 에러는 throw가 던진 에러를 잡을 때처럼 try..catch문법을 사용해 잡을 수 있다.

참고:

ko.javascript :프라미스와 async, await

This post is licensed under CC BY 4.0 by the author.

브라우저 작동원리와 성능 최적화

NodeJS와 NPM

Comments powered by Disqus.