본문 바로가기
Frontend/엘리스 SW 엔지니어 트랙

[ 엘리스 SW 엔지니어 트랙 ] 17일차

by YWTechIT 2021. 11. 17.
728x90

📍 17일 차 11.17. 수.(온라인 강의)

오늘은 어제 배웠던 동기 / 비동기, 콜백함수, promise에 대해 더 자세하게 배웠다. promise는 3~4개월 전인가? 토스 코딩 테스트에서 비동기적으로 api 호출하는 테스트가 나왔었는데, 그때 문제의 의도를 정확하게 파악하지 못해서 틀렸던 경험이 있었다. 프론트엔드와 비동기는 떼려야 뗄 수 없는 관계이므로 잘 기억하자.


❏ 자바스크립트 제어 흐름

  1. 자바스크립트는 다른 멀티스레드 프로그래밍 언어(JAVA, C++)와 다른 방식으로 비동기 동작을 처리한다.
  2. 처음 자바스크립트를 접하는 경우, 동작에 대한 정확한 이해가 없으면 코드의 흐름을 따라가기 어렵다.
  3. 자바스크립트 내부의 비동기 동작을 이해하기 위해서는 이벤트 루프 등의 개념을 알아야만 한다.
  4. JS 엔진은 하나의 메인 스레드로 구성된다.
  5. 메인 스레드는 코드를 읽어 한 줄 씩 실행한다.
  6. 브라우저 환경에서는 유저 이벤트를 처리하고 화면을 그린다.

❏ 동기적 제어 흐름

  1. 동기적 제어 흐름은 현재 실행중인 코드가 종료되기 전까지 다음 라인의 코드를 실행하지 않는 것을 의미한다.
  2. 분기문, 반복문, 함수 호출은 동기적으로 실행된다.
  3. 코드의 흐름과 실제 제어 흐름이 동일하다.
  4. 싱글 스레드 환경에서 메인 스레드를 긴 시간 점유하면, 프로그램을 멈추게 한다.

❏ 비동기적 제어 흐름

  1. 비동기적 제어 흐름은 현재 실행중인 코드가 종료되기 전에 다음 라인의 코드를 실행하는 것을 의미한다.
  2. 프로미스 ,콜백 함수 등은 비동기적으로 실행된다.
  3. 코드 흐름과 실제 제어 흐름이 다르다.
  4. 비동기 작업을 기다리는 동안 메인 스레드는 다른 작업을 처리한다.

❏ 이벤트 루프

  1. JS 엔진은 비동기 처리를 제공하지 않는다.
  2. 대신, 비동기 코드는 정해진 API(setTimeout, XMLHttpRequest, fetch)를 제공하여 활용할 수 있다.
  3. node.js 의 경우 파일 처리 API, 암호화 API 등을 제공한다.
// 타이머 비동기 처리
setTimeout(() => console.log("타이머 끝"), 1000);
setInterval(() => console.log("인터벌 타이머"), 1000);

// 네트워크 처리
fetch("https://google.com")
        .then(() => console.log("네트워크 요청 성공"))
        .catch(() => console.log("네트워크 요청 실패"))
  1. 비동기 코드를 처리하는 모듈은 JS 엔진 외부에 있다.
  2. event queue, task queue, job queue 등으로 구성된다.
  3. API 모듈은 비동기 요청을 처리 후 태스크 큐에 콜백 함수를 넣는다.
  4. JS 엔진은 콜 스택이 비워지면, event Loop에서 task queue의 콜백 함수를 call stack으로 push한다.
  5. call stack에 있는 콜백 함수가 실행된다.
// 비동기 처리가 끝나면 콜백 함수를 task queue로 밀어 넣는다.
request("user-data", (userData) => {
    console.log("userData 로드")
    saveUsers(userData)
})

console.log("DOM 변경");
console.log("유저 변경");

 

728x90

❏ Promise

  1. 비동기 API 중 하나이다.
  2. 태스크 큐가 아닌 잡 큐(Job queue 혹은 Microtask queue)를 사용한다.
  3. 잡 큐는 태스크 큐보다 우선순위가 높다.
setTimeout(() => {
  console.log("타임아웃1")
}, 0);

Promise.resolve().then(() => console.log("프로미스 1"));

setTimeout(() => {
  console.log("타임아웃2")
}, 0);

Promise.resolve().then(() => console.log("프로미스 2"));

👉🏽 프로미스 1 프로미스 2 타임아웃1 타임아웃2
  1. 비동기 작업을 표현하는 자바스크립트 객체
  2. 비동기 작업의 진행, 성공, 실패 상태를 표현한다.(new Promise(resolve, reject), fetch(promise 반환))
  3. 비동기 처리의 순서를 표현할 수 있다.
  4. then, catch, finally, then(cb1, bc2)cb1 자리에 성공, cb2 자리에 실패 메서드를 인자로 넘길 수 있다.
  5. promise method chain: then / catch 메서드가 또 다른 promise 를 리턴하여, 비동기 코드에 순서를 부여한다. 동일한 객체에 메서드를 연결할 수 있는 것을 체이닝이라고 한다. 함수를 호출한 주체가 함수를 끝낸 뒤 자기 자신을 리턴하도록 하여 구현한다. (함수의 끝에 return this가 생략되어있기 때문에 가능하다.), 비동기 코드의 순서를 쉽게 부여 가능하다.
promise
    .then((data) => {
        return fetchUser(data);
    })
    .then((user) => {
        console.log("user : ", user);
    })
    .catch((e) => {
        console.log("실패 : ", e);
    });
  1. Promise.resolve(10).then(console.log) : 성공한 Promise 를 바로 반환한다. 인위적으로 Promise 메서드 체인을 만들 수 있다. 비동기 코드로 진행해야 하는 상황 등에 유용하게 사용할 수 있다.
  2. Promise.reject("Error").then(console.log): 실패한 Promise 를 바로 반환한다.
Promise.resolve(10).then(() => console.log("성공"))
👉🏽 성공

Promise.reject(new Error("에러!")).then(() => console.log("실패"))
👉🏽 (node:24270) UnhandledPromiseRejectionWarning: Error: 에러!
  1. promise.all: 모든 promisesettled 될 때까지 기다린다. 만약, promise 의 배열을 받아 모두 성공하면 각 promiseresolved 값을 배열로 반환한다. 하나의 promise 라도 실패하면 가장 먼저 실패한 promise 의 실패 이유를 반환한다.
Promise.all([
  promise1,
  promise2,
  promise3,
])
  .then((values) => {
    console.log("모두 성공", values)
  })
  .catch((e) => {
    console.log("하나라도 실패", values)
  })
  1. promise를 리턴하는 값이 같으면 then 을 생략할 수 있다
// 2개의 API에 모두 then을 사용한 방식
promise
    .then((item) => getUserNameById(item.id))
    .then((id) => id)
  .catch(e => e.message);

// 2개의 API 중 한개만 then을 사용한 방식
promise
    .then((item) => getUserNameById(item.id))
  .catch(e => e.message);
반응형

댓글