데브코스 17일차 ( 24.11.05 화 ) JavaScript

워니·2024년 11월 5일
0

Programmers Front-end

목록 보기
17/27

[Section 03] JavaScript 동기 비동기


< 배운 내용 요약 정리 >

< 문제 풀다가 다시 정리하는 개념 >
  예를 들어 count가 배열이면 count[]에서 []안의 값은 인덱스(숫자)를 의미하고,
  count가 객체면 count[]에서 []안의 값은 속성의 키를 의미한다.
  ex) 배열일 때
  const count = [10, 20, 30];
  console.log(count[1]); // 20 (1번 인덱스의 값)
  ex) 객체일 때
  const count = { "1": "one", "2": "two" };
  console.log(count[1]); // "one" (키가 "1"인 속성에 접근)
  

1. 동기 vs 비동기
- 하나의 작업만 순서대로 진행 vs 작업을 기다리지 않고 다음 작업 진행
2. 일반적인 자바스크립트 엔진 vs 웹브라우저 자바스크립트 엔지
- 콜스택 vs 태스크 큐
- 비동기 함수는 콜스택이 아닌 태스크 큐에서 처리 : 이벤트 루프
3. 대표적인 비동기 함수
- setTimeout(), setInterval(), fetch()
4. 비동기 함수 처리 방법
- callback : 동기 / 비동기
- promise : 생산자 생성할 때 사용하는 표준내장객체, producer / consumer
- async ... await (오늘 안 다뤘음)

< 19. 동기와 비동기 >

1. 동기와 비동기

1.1. 동기

  • 싱글 스레드를 가지고 있는 언어
  • 일을 할 수 있는 작업장이 한 개하는 뜻
  • 한 번에 하나의 작업만 수행하며, 코드가 작성된 순서대로 실행

1.2. 비동기

  • 한 작업이 완료되기를 기다리지 않고 다음 작업으로 넘어갈 수 있음
  • 자바스크립트는 기본적으로 단일 스레드로 동작하지만,
    이벤트 루프콜백 큐를 통해 비동기 처리를 효율적으로 관리할 수 있음
  • 이해를 도울 사이트
    latentflip.com

2. 자바스크립트 엔진

2.1. 일반적인 자바스크립트 엔진

2.2. 웹 브라우저에 탑재된 자바스크립트 엔진

  • 콜스택의 작업이 모두 비워진 이후, 태스크 큐에 대기하고 있던 콜백이 들어감
  • 콜스택이 비워지지 않으면 태스크 큐에 대기 중인 콜백이 들어갈 수 없음
  • 먼저 실행된 것이 있다면 작성 순서에 상관 없이 실행된 순서대로 대기 후 들어감
  • 이벤트 루프 : 웹 브라우저 자바스크립트 엔진에서 일어나는 일련의 과정들
  • 비동기는 웹 브라우저에 탑재되어 있는 엔진의 도움을 받아 실행 가능한 것

2.2.1. 크롬 : v8 엔진

2.2.2. 파이어폭스 : 스파이더몽키 엔진

2.2.3. 사파리 : 자바스크립트코어 엔진


3. 대표적인 비동기 함수

3.1. setTimeout(), setInterval(), fetch()

  • WEB API에 속함, 웹 브라우저에서부터 제공을 받음
  • WEB API의 공통점은 콜백이 있다는 것
  • 웹 브라우저의 자바스크립트 엔진에서 실행됨
    • 자바스크립트 엔진은 콜스택을 가짐, 웹브라우저 엔진은 태스크 큐를 가짐
  • setTimeout()
    • 설정 시간만큼 대기 후 실행이 됨

4. 비동기 함수를 적절하게 처리하는 방법

  • callback, promise, async...await

< 20. Callback 함수 >

  • 함수의 매개변수로 전달되는 함수

1. 동기 콜백 함수

  • 동기적으로 실행되는 상태에서 활용되는 콜백
// ex)
function a(callback) {
  console.log("a");
  callback();
}
function b() {
  console.log("b");
}
a(b); // a, b

2. 비동기 콜백 함수

  • 비동기적으로 실행되는 상태에서 활용되는 콜백
// ex)
function a() {
  setTimeout(() => {
    console.log("a");
  }, 0);
}
function b() {
  console.log("b");
}
a();
b();
// b, a가 출력됨

// ex ) 비동기 콜백함수
// a, b 순서로 출력되게 하고 싶으면 callback 함수를 사용
function a(callback) {
  setTimeout(() => { // 비동기 함수 setTimeout으로 인해 순서가 바뀜
    console.log("a");
    callback();
  }, 0);
}
function b() {
  console.log("b");
}
a(b); // a, b

※ 화살표 함수의 탄생 배경

  • 매개변수로 전달되는 callback 함수를 간단하게 하기 위해 생김
// ex)
function a(callback) {
  setTimeout(() => {
    console.log("a");
    callback();
  }, 0);
}
a(() => {
  console.log("b");
});

※ 비동기의 단점

  • 1234순으로 출력되게 하고 싶은데 비동기 함수가 있으면 순서가 꼬임
  • callback 함수 자체를 새로운 함수로 전달해서 해결할 수 있음
  • 예시
    // ex )
    function task1() {
      console.log("task1");
    }
    function task2() {
      console.log("task2");
    }
    function task3() {
      console.log("task3");
    }
    function task4() {
      console.log("task4");
    }
    task1();
    task2();
    task3();
    task4();
    // task1, task2, task3, task4
    
    // ex 2)
    function task1() {
      setTimeout(() => {
        console.log("task1");
      });
    }
    function task2() {
      console.log("task2");
    }
    function task3() {
      setTimeout(() => {
        console.log("task3");
      });
    }
    function task4() {
      console.log("task4");
    }
    task1();
    task2();
    task3();
    task4();
    // task2, task4, task1, task3 비동기때문에 순서가 다 뒤틀림
    
    // ex 3) 콜백 지옥 패턴
    function task1(callback) {
      setTimeout(() => {
        console.log("task1");
        callback(); // callback 추가
      }, 0);
    }
    function task2(callback) {
      console.log("task2");
      callback();
    }
    function task3(callback) {
      setTimeout(() => {
        console.log("task3");
        callback();
      }, 0);
    }
    function task4() {
      console.log("task4");
    }
    task1(() => {
      task2(() => {
        task3(() => {
          task4();
        });
      });
    });
    // task1, task2, task3, task4 순으로 출력됨

< 21. Promise 함수 >

  • 자바스크립트 비동기 작업을 처리하기 위한 객체
  • 비동기 작업의 성공 또는 실패를 나타내는 정보를 가지고 있다.
  • 보통 생성자 함수처럼 new Promise()형태로 호출하여 인스턴스 생성
  • Producer vs Consumer 역할로 구분
< 기본적인 문법 형태 >

new Promise(function(resolve, reject) {
    // 비동기 작업을 수행하는 코드
    // 작업이 성공하면 resolve(value) 호출
    // 작업이 실패하면 reject(error) 호출
});

1. Producer(생산자)

  • 비동기 작업을 실행하는 코드
  • resolvereject가 무조건 사용되어야 한다.
  • 상태: pending, fulfilled, rejected
  • pending : 코드가 실행되었으나 응답은 오지 않은 상태
  • fulfilled : 코드가 성공적으로 실행된 상태 (이행)
  • rejected : 코드가 실패한 상태 (거부)
  • 예시
    // ex )
    const promise = new Promise(function (resolve, reject) {
      // executor 콜백함수를 받는다
      // 비동기 로직 작성
      setTimeout(() => {
        resolve("success");
      }, 2000);
      // 콘솔에 pending이지만 지정 시간 후 펼쳐보면 fulfilled 상태가 됨
      // resolve 대신 reject 넣으면 rejected 상태가 됨
    });
    console.log(promise); // 처음에는 pending 상태

2 Consumer(소비자)

  • then, catch, finally
  • then : resolve가 호출되면 실행되는 함수
  • catch : reject가 호출되면 실행되는 함수
  • finally : then, catch의 마지막에 보통 하나만 사용
    (맨 끝 아니라도, 하나가 아니라도 가능은 함), 무조건 실행됨
  • 예시
    // ex )
    const promise = new Promise(function (resolve, reject) {
      setTimeout(() => {
        reject("failed"); // new Error("failed")라고 작성하면 에러가 뜸
      }, 1000);
    });
    promise
      .then((value) => {
        console.log(value);
      }) // resolve 값 반환
      .catch((err) => {
        console.log(err);
      }); // reject 값 반환
    
    // ex 2)
    // 영화 예매
    const startBooking = () => {
      console.log("영화 예매 시작");
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          //...
          console.log("영화 예매 완료");
          resolve("영화 예매 완료");
        }, 1000);
      });
    };
    // 영화 선택
    const selectMovie = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const movie = "어벤져스";
          resolve(`${movie} 선택`);
        }, 1000);
      });
    };
    // 좌석 선택
    const selectSeat = () => {};
    // 결제
    const makePayment = () => {};
    // 영화 감상
    const watchMovie = () => {};
    
    startBooking() //
      .then((value) => selectMovie(value))
      // 반환된 값을 또 다른 then에서 받아서 사용할 수 있다
      .then((value) => {
        console.log(value);
      });
    
    // ex 3)
    const fetchNumber = new Promise((resolve, reject) => {
      // Promise는 코드가 읽히는 순간 실행이 되어 버린다.
      setTimeout(() => {
        resolve(2);
      }, 1000);
    });
    
    fetchNumber //
      .then((num) => num * 2)
      // return reesolve(value*2)와 같아
      // 그러므로 반환된 값을 아래 then에서 받아서 사용이 가능함
      .then((num) => num * 2)
      .then((num) => {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve(num * 2);
          }, 1000);
        });
      })
      .then((num) => {
        console.log(num);
      });

3 promise then 체이닝

  • 예시
    // ex 1)
    const fetchNumber = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(2);
      }, 1000);
    });
    
    fetchNumber //
      .then((num) => num * 2)
      .then((num) => num * 2)
      .then((num) => {
        return new Promise((resolve, reject) => {
          resolve(num);
        });
      })
      .then((num) => {
        console.log(num);
      })
      // callback 매개변수에서 resolve 값을 받을 의무는 없다
      // 하지만 그 값을 이용해 활용할 수 있다는 것
      .catch(() => {});
    
    // ex 2)
    const getSunIcon = () => {
      return new Promise((resolve, _) => {
        setTimeout(() => {
          resolve("😄");
        }, 1000);
      });
    };
    const getPlantIcon = (water) => {
      return new Promise((resolve, _) => {
        setTimeout(() => {
          resolve(`${water} => 😒`);
        }, 1000);
      });
    };
    getSunIcon() //
      .then((sun) => getPlantIcon(sun))
      .then((water) => console.log(water));

4 Task QueueMicro Task Queue

  • Task Queue보다 Micro Task Queue가 먼저 실행되어 출력된다.
  • setTimeout과 같은 비동기 함수는 Task Queue에 담기고, then과 catch, finally는 Micro Task Queue에 담기므로 비동기 함수보다 then의 순서에 맞게 출력

< 하루 정리 >

오늘은 수업 시작 전 문제를 두 개 먼저 풀고 시작을 했다.
어제 팀원들이랑 공유한 부분, 그리고 용재님께서 알려주신 부분이 있어서인지
문제를 풀 때 좀 더 머리 회전이 된 것 같은 기분이었다.
(물론 엉뚱한 곳에서 시간이 오래걸려서 시간 내 제출은 못 했지만..)

수업 내용은 전반적으로 크게 어려운 느낌은 아니었지만, 그렇다고 바로 이해가 되지도 않았다.
강사님께서 여러가지 예시를 보여주시기 위해 많은 드리블(?)하셨고
그 과정에서 중간중간 놓칠 때 마다 멘탈이 흔들리기 시작했다..

저번 주부터 시작됐지만, 수업 내용이 어렵고 머릿 속에 혼란이 찾아 올 때마다
팀원들과 사이가 돈독해지고 있다 ㅋㅋㅋ
다들 나만큼은 아니더라도 어렵긴 어려운 듯...ㅠㅠ

그래도 수업 내용이 이해가 안 되는게 있으면 팀원들과 먼저 내용을 공유하고
부족한 부분을 채워나갈 수 있어서 참 좋은 것 같다.

마지막에 해결되지 않은 깃허브도 물론 강사님이 원하셨던 방법은 아니었지만,
팀원들의 도움으로 어찌 해결하긴 했다.

잠을 4시간 정도 밖에 못 자서 몸이 피곤한데도, 
많은 걸 느끼고 많은 걸 배우고 많은 걸 해결해서 기운은 나는 하루!!
profile
첫 시작!

0개의 댓글