Post

[js] 자바스크립트의 일급함수의 성질에 기반한 콜백함수의 비동기 처리 및 Promise, async / await

자바스크립트의 특이한 일급함수로써의 성질

🐀 함수가 변수처럼 할당될 수 있다

값처럼 사용할 수 있는 객체*일급객체라 한다.
자바스크립트의 함수는 호출가능한 객체로써, 피연산자로 사용될 때 함수 리터럴(값)로 해석된다.
즉, 하나의 값처럼 동작하는 함수를 다른 함수의 인자(args)로써 전달할 수 있고, 이를 파라미터로 받을 수 있다.
단, 함수는 호출되기 이전에, 함수 코드블록의 어떤 것도 실행되지 않는다.

함수 정의 방식

🐙 함수 정의 방식
  • 함수 선언문
    선언문이기 때문에 함수 호이스팅이 일어난다.
    함수이름과 동일한 이름의 식별자가 생성, 함수 객체가 할당
    1
    2
    3
    
    function add(x, y) {
      return x + y;
    }
    
  • 함수 표현식
    함수 리터럴로 생성함 함수 객체가 변수에 할당
    1
    2
    3
    
    let add = function (x, y) {
      return x + y;
    };
    
  • Function 생성자 함수

    1
    
    let add = new Function("x", "y", "return x + y");
    
  • 화살표 함수
    ECMAScript6 반복되는 표현들 때문에 간소화된 문법
    1
    
    let add = (x, y) => x + y;
    
    • 축약문법
      • 코드블록 안에 return문만 있을 때, 중괄호 및 return 예약어 제거 가능
        1
        
        const sum = () => 10 + 20;
        
      • 파라미터가 하나인 경우, 괄호제거 가능
        1
        2
        3
        4
        
        const logNum = (num) => {
          console.log(num);
          return num;
        };
        
  • 즉시 실행 함수
    그룹 연산자 ()로 감싸면 함수 리터럴로 평가되어 함수 객체를 생성
    1
    2
    3
    4
    5
    
    (function () {
      let a = 3;
      let b = 5;
      return a + b;
    })();
    

콜백함수

🐁 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백함수라 한다

※ 인수로 함수를 받는 함수를 고차함수라 한다.

🐝 콜백함수를 이용한 비동기 처리.js

1
2
3
setTimeout(function () {
  console.log("1초 경과");
}, 1000);

🐝 콜백함수를 이용한 배열 고차함수.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let res = [1, 2, 3].map(function (item) {
  return item * 2;
});
console.log(res); // [2, 4, 6]

res = [1, 2, 3].filter(function () {
  return item % 2;
});
console.log(res); // [1, 3]

res = [1, 2, 3].reduce(function (acc, cur) {
  return acc + cur;
});
console.log(res); // 6

비동기 처리

🐁 특정 로직의 실행이 끝날 때까지 기다리지 않고, 다음 코드를 실행하는 처리 방식을 비동기 처리라 한다

요청을 하고 데이터를 받아올 때까지 기다려주는 코드가 없으면,
데이터를 다 받아오기도 전에 다음 코드가 실행되어 원하는 값을 얻을 수 없다.

1
2
3
4
5
6
7
8
9
10
function fetchMenu() {
  setTimeout(() => {
    let data = { firstMenu: "구독" };
    return data;
  });
}

let menu = fetchMenu();

console.log("menu", menu); //menu undefined

콜백함수를 사용하면 특정 로직이 끝났을 때, 원하는 동작을 실행시킬 수 있다.
즉, 일급함수의 성질을 이용해 함수를 파라미터로 전달하고, 전달된 함수를 호출할 수 있다.

🐝 callback.js

1
2
3
4
5
6
7
8
9
10
11
12
13
function fetchMenu(callback) {
  setTimeout(() => {
    let data = { firstMenu: "구독" };
    callback(data);
  }, 5000);
}

let menu;
fetchMenu(function (result) {
  console.log("5초뒤 실행", result);
  menu = result;
  console.log("menu", menu);
});

콜백함수를 연속해서 사용할 때, 가독성이 떨어진다.
또한, 매번 에러처리를 위한 인자를 추가해야하며, 분기해야 한다.

결과를 나타낸다는 약속, Promise

🌋 Promise는 JavaScript 비동기 처리에 사용되는 객체다

연속된 콜백함수 사용으로 인해 낮아지는 가독성 문제를 해결할 수 있다.

📕 Promise 상태
- Pending(대기상태): 비동기 처리 로직이 아직 완료되지 않은 상태

- Fulfilled(이행상태): 비동기 처리가 완료되어 Promise가 결과값을 반환해준 상태
⚠️ 콜백함수의 인자 resolve를 호출하면 Fufilled 상태가 된다.
⚠️ Fulfilled 상태가 되면 then()을 이용하여 처리 결과값을 받을 수 있다.

- Rejected(실패상태): 비동기 처리가 실패하거나 오류가 발생한 상태
⚠️ 콜백함수의 인자 reject를 호출하면 Rejected 상태가 된다.
⚠️ Rejected 상태가 되면 error를 catch()로 받을 수 있다.

🐝 promise.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function fetchMenu() {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      let data = { firstMenu: "구독" };
      if (error) {
        reject(new Error("Request is failed"));
      }
      resolve(data);
    }, 5000);
  });
}

let menu;
fetchMenu()
  .then(function (result) {
    console.log("5초 뒤 실행", result);
    menu = result;
    console.log("menu", menu);
  })
  .catch(function (error) {
    console.log("에러 처리");
    return;
  });

🍪 체이닝 - 여러 개의 Promise를 연결하여 사용할 수 있다.
then() 메서드를 호출하고 나면 새로운 Promise객체가 반환된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
})
  .then(function (result) {
    console.log(result); //1
    return result + 10;
  })
  .then(function (result) {
    console.log(result); //11
    return result + 20;
  })
  .then(function (result) {
    console.log(result); //31
  });

☄️ Promise 2가지 에러 처리
(1) then() 메서드의 두번째 인자
(2) catch() 권고
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getData() {
  return new Promise(function (resolve, reject) {
    resolve("hi");
  });
}

getData().then(
  function (result) {
    console.log(result);
    throw new Error("Error in then()"); // 여기서 오류가 나는 경우
  },
  function (err) {
    // 오류를 잡아내지 못한다
    console.log("then error= ", err);
  }
);

개발자가 읽기 좋은 비동기 처리 코드, async / await

🍝 해당 문법도 내부적으로는 Promise를 사용한다

🐝 async_await.js

1
2
3
4
5
6
7
8
9
10
11
12
async function init() {
  try {
    let menu;
    menu = await fetchMenu();
    await renderPageUI(); // 체이닝
    console.log("menu", menu);
  } catch (error) {
    console.log("에러처리");
  }
}

init();

Promise를 반환하는 함수 앞에 await를 붙여주면 마치 동기 처리를 구현하는 것처럼, 비동기 처리를 구현할 수 있다.
해당 문법의 예외처리는 자바스크립트의 기존 try / catch 문법을 이용하면 된다.

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