[Codeit boost 1기] JS 중급 (3)

김서윤·2024년 6월 19일
0
post-thumbnail

Ch3. 비동기 자바스크립트


1️⃣ 토픽 시작하기

01. 토픽 소개

JS

  • 웹에 사용하기 위해 만들어진 언어
  • 웹에서는 리퀘스트를 보내거나 사용자의 상호 작용을 기다려야 하는 일이 많음
  • 비동기 프로그래밍이 특히 많이 쓰임

비동기 프로그램

: 주어진 코드를 순서대로 진행하는 것이 아니라 오래 기다려야하는 작업이 있으면 다음 작업을 먼저 처리하고 나중에 처리하던 작업으로 다시 돌아와서 마무리하는 방식

  1. 콜백 (Callback)
  2. 프로미스 (Promise)

2️⃣ 콜백과 비동기 실행

01. 파라미터 vs 아규먼트

function add(x, y) {
  return x + y;
}

add(1, 2);

→ 파라미터 : x, y

: 함수에 전달받은 값을 함수 내부로 전달하기 위해 사용하는 변수

→ 아규먼트 : 1, 2

: 함수에 실제로 전달되는 값

02. 콜백(Callback)이란?

→ 어떤 함수의 아규먼트로 전달되는 함수를 콜백 또는 콜백 함수

콜백(Callback) 함수 : 아규먼트로 전달되는 함수

  • 간단한 콜백에서는 Arrow Function을 자주 사용
function sayHello(name) {
  console.log(`Hello ${name}!`);
}

function sayGoodbye(name) {
  console.log(`Goodbye ${name}!`);
}

function printMessage(func, name) {
  console.log("Printing message...");
  func(name);
}

printMessage((name) => console.log(`Hello ${name}!`), "Bob");

03. forEach() 함수 만들기

  • 실습 코드
    function forEach(array, callback) {
      for (let elt of array) {
        callback(elt);
      }
    }
    
    const words = ['JavaScript', 'Java', 'Python'];
    
    // 배열의 요소를 출력하세요. Arrow Function을 사용하세요.
    forEach(words, (word) => console.log(word));
    
    function printUpper(word) {
      const upper = word.toUpperCase();
      console.log(upper);
    }
    
    // 배열의 요소를 대문자로 출력하세요. function 키워드로 함수를 선언하고 콜백으로 전달하세요.
    forEach(words, printUpper);

04. 콜백과 비동기 함수

console.log("1");

setTimeout(() => console.log("2"), 3000);

console.log("3");

// 1 3 2

→ 오래 걸리는 작업이 있을 때 시간을 절약 → 효율적인 코드

⚡️ 비동기 함수 (Asynchronous Function)

: 함수의 내용을 끝까지 쭉 실행하지 않고 중간에 다른 작업을 처리하다가 다시 돌아와서 마무리를 하는 함수

  • 자바스크립트나 자바스크립트 라이브러리는 다양한 비동기 함수를 제공해 줌
  • 제공되는 비동기 함수에 콜백을 넘겨주기만 하면 비동기 프로그램을 구현할 수 있음

05. setTimeout() 함수 사용해 보기

  • 실습 코드
    function sayHello(name) {
      console.log(`Hello ${name}!`);
    }
    
    console.log('시작');
    
    // setTimeout(sayHello, 2000, 'Codeit');
    setTimeout((name) => console.log(`Hello ${name}!`), 2000, 'Codeit');
    
    console.log('끝');

06. 비동기 실행 파헤치기

  1. 비동기 함수는 이후에 있는 코드를 모두 실행하고 콜백을 실행한다
  2. 실행할 콜백이 여러 개일 경우, 동기적으로 실행된다

07. 비동기 함수의 예시들

  1. setTimeout() 함수

    1. setTimeout() 이전에 있는 코드 실행
    2. setTimeout() 함수 실행: delay 만큼 기다리는 타이머를 시작
    3. setTimeout() 이후에 있는 코드 실행
    4. delay가 지나면 callback 실행
  2. setInterval() 함수

    : 시간 간격을 두고 콜백을 반복적으로 실행

    setInterval(callback, interval) : interval 단위는 밀리초입니다.

    setInterval(() => console.log('2초가 지났습니다'), 2000);

  3. DOM의 addEventListener() 함수

    const btn = document.querySelector('.my-btn');

    btn.addEventListener('click', () => console.log('button clicked!'));

  4. React의 useEffect() 함수

    : 콜백을 바로 실행하지 않고 일단 화면을 그리기 때문에 웹 페이지가 더 빨리 로딩되는 것처럼 보이게 할 수 있음

    useEffect(() => console.log('render finished!'), []);

  5. Express의 get() 함수

    : 리퀘스트가 언제 들어올지를 모르기 때문에 리퀘스트에 대한 처리는 비동기 형태로, 콜백에 파라미터 존재

    app.get('/hello', (req, res) => {
      res.send('Success!');
    });

08. 콜백 헬(Callback Hell)

→ 콜백이 여러번 중첩되는 것

→ 여러 비동기 작업을 연속적으로 처리한다는 문제점

→ 문제를 해결하기 위해 Promise 문법 생성

3️⃣ Promise

01. Promise란?

Promise 객체fetch("api 링크");

  • 비동기 작업이 완료되면 값을 알려주는 객체
  • 작업이 완료되면 값을 알려줄 것을 ‘약속’함

콜백 기반

getEmployees((response) => {
	json(response, (data) => {
		console.log(data);
	});
});

Promise 기반

const response = await fetch('...');
const data = await response.json();
console.log(data);

Promise를 다루는 방법

  1. .then() 메소드 + 콜백
  2. asyncawait 문법

02. await 문법

const response = await fetch('...');
const data = await response.json();
console.log(data);

Promise를 리턴하는 표현식이 있다면, 앞에 await 키워드를 사용하여 결과값(파싱된 데이터)을 받아올 수 있다.

await을 사용하면 Promisefulfilled 상태가 될 때까지 기다렸다가 결과값을 돌려준다.

✨ Promise의 3가지 상태

  1. Pending : 비동기 작업의 결과를 기다리고 있는 상태
  2. Fulfilled : 비동기 작업이 성공적으로 완료된 상태
  3. Rejected : 비동기 작업이 중간에 실패한 상태

03. 점심 메뉴 받아오기 1

  • 실습 코드
    // 여기에 코드를 작성하세요.
    const response = await fetch('...');
    const data = await response.json();
    console.log(data);

04~05. async 함수

→ 제대로 된 비동기 함수로 사용하려면 추가적인 과정 필요

await : async 함수 내에서 or 모듈의 최상위 레벨에서만 사용 가능

main.js

import { printEmployees } from "./asyncFunctions";

printEmployees();

console.log("Task 2");

console.log("Task 3");

// Task 2
// Task 3
// printEmployees 실행결과

asyncFunctions.js

export async function printEmployees() {
  const response = await fetch("...");
  const data = await response.json();
  console.log(data);
}

/*
const printEmployees = async () => {
  const response = await fetch("...");
  const data = await response.json();
  console.log(data);
}
*/

06. 점심 메뉴 받아오기 2

  • 실습 코드
    // 여기에 코드를 작성하세요.
    export async function printMenus() {
      const response = await fetch('...');
      const data = await response.json();
      console.log(data);
    }

07. 효율적인 비동기 코드

  • 비효율적인 코드 (수많은 await문을 호출)
async function getEmployees() {
  for (let i = 1; i < 11; i++) {
    const response = await fetch(`.../${i}`);
    const data = await response.json();
    console.log(data);
  }
}

getEmployees();
  • 효율적인 코드 (순서는 지켜지지 않지만 한번에 리퀘스트를 전송)
async function getEmployee(id) {
  const response = await fetch(`.../${id}`);
  const data = await response.json();
  console.log(data);
}

for (let i = 1; i < 11; i++) {
  getEmployee(id);
}

08. async 함수의 리턴값

항상 Promise를 리턴한다❗️

const employees = getEmployees(); // Promise
console.log(employees)

09. 점심 메뉴 랜덤 선택기

  • 실습 코드
    import { getMenus } from './asyncFunctions.js';
    
    function getRandomElement(arr) {
      const randomIdx = Math.floor(Math.random() * arr.length);
      return arr[randomIdx];
    }
    
    console.log('메뉴 고르는 중...');
    
    const menus = await getMenus();
    
    const randomMenu = getRandomElement(menus);
    
    console.log(`오늘의 랜덤 메뉴는 ${randomMenu.name}입니다!`);

10. 신입 직원 추가하기

  • 실습 코드
    import { getInterviews, getEmployees } from './asyncFunctions.js';
    
    function addNewEmployee(employees, interview) {
      const { name, department } = interview;
      const newEmployee = {
        id: employees.length + 1,
        name,
        department,
        email: `${name}@codeitmall.kr`,
      };
      employees.push(newEmployee);
    }
    
    const employees = await getEmployees();
    
    const interviews = await getInterviews();
    
    interviews.forEach((interview) => {
      if (interview.result === 'pass') {
        addNewEmployee(employees, interview);
      }
    });
    
    console.log(employees);

11. try catch로 오류 처리하기

export async function getEmployees() {
  try {
    const response = await fetch("...");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.log("Error!");
    return;
  } finally {
    console.log("Finished");
  }
}

catch문 속에서는 에러 처리 가능

return 시 함수를 종료

finallyreturn 해도 실행하고 함수 종료

12. 고장난 점심 메뉴 선택기

  • 실습 코드
    export async function getMenus() {
      // 여기에 코드를 작성하세요.
      try {
        const response = await fetch('...');
        const menus = await response.json();
        return menus;
      } catch(error) {
        console.log('데이터를 가져오지 못했습니다 :(');
      } finally {
        console.log('getMenus() 함수가 끝났습니다.'); 
      }
    }

13. Promise와 오류 제대로 이해하기

14~15. .then() 메소드

.then() 메소드 : 앞선 비동기 작업이 완료되면 등록된 콜백을 실행 (Promise 객체의 메소드)

async function getEmployees() {
  const response = await fetch("...");
  const data = await response.json();
  console.log(data);
}

// const dataPromise = fetch("...").then((response) => response.json());
// dataPromise.then((data) => console.log(data));

fetch("...")
	.then((response) => response.json())
	.then((data) => console.log(data));

16~17. .catch()와 .finally() 메소드

fetch("...")
  .then((response) => response.json())
  .then((data) => console.log(data))
  .**catch((error) => console.log("Error!"))
  .finally(() => console.log("Finished"));**

→ 위와 같은 역할

catch문 속에서는 에러 처리 가능

finallyreturn 해도 실행하고 함수 종료

18. Promise.all() 메소드

async function getEmployee(id) {
  const response = await fetch(`.../${id}`);
  const data = await response.json();
  return data;
}

const promises = [];

for (let i = 1; i < 11; i++) {
  promises.push(getEmployee(i));
}

const employees = await Promise.all(promises); // try, catch도 가능
console.log(employees);

→ 여러 Promise를 동시에 기다릴 때 사용

19. 리퀘스트 동시에 보내기

  • 실습 코드
    import { getEmployees, getMenus } from './asyncFunctions.js';
    
    const employeesPromise = getEmployees();
    const menusPromise = getMenus();
    
    const [employees, menus] = await Promise.all([employeesPromise, menusPromise]);
    
    // 테스트 코드
    console.log('직원 데이터:');
    console.log(employees);
    console.log('메뉴 데이터:');
    console.log(menus);

0개의 댓글

관련 채용 정보