동기, 비동기 프로그래밍

hatban·2023년 4월 3일
0

동기(Sync)

어떠한 작업이 순차적으로 실행되는 개념
요청을 하면 결과가 반환되는 것을 기다린다

  • 매우 직관적인 설계방식
  • 결과 반환까지 기다려야하는 단점이 존재

비동기(Async)

어떠한 작업들이 동시에 일어날 수 있는 개념
요청을 하면 결과 반환을 기다리지 않고 다음 작업이 바로 수행

  • 병렬적으로 수행해 효율적이다
  • 설계가 복잡하다는 단점


자바스크립트의 비동기

  • 자바스크립트는 싱글쓰레드로 단 하나의 작업만 돌아간다
  • 하지만 비동기로 처리한다!

전체 source를 순회하는 쓰레드는 하나지만, DB를 조회하는 등의 시간 비용이 많이 드는 작업은 다른쓰레드로 위임하고 계속 소스를 순회한다

  • 이때 API라는 곳에 위임시킨다
  • API에 던져준 일을 API가 끝내면 이벤트 큐에 등록이 되고 대기
  • 메인스레드의 일이 다 끝나 CallStack이 비게되면, 이벤트 루프가 이벤트 큐에있는 일을 하나 꺼내서 CallStack에 밀어넣어준다.

자바스크립트의 비동기처리 방법

  1. 콜백함수
  2. Promise
  3. Async/Await

1. Callback

  • 함수의 인자로 들어가는 함수
  • 콜백함수를 넣어 함수의 결과물을 필요로하는 로직을 처리한다

이러한 콜백함수는 콜백함수 안에서 다른 콜백함수를 부르고 결국 콜백지옥에 빠져서 가독성이 매우 나쁘다!


2. Promise

  • 콜백지옥을 벗어나기 위한 객체
  • 비동기 처리를 하는 함수가 끝난 뒤 Promise객체를 반환하면 then 키워드로 그 다음처리를 하거나 catch 키워드로 에러 처리를 할 수 있다.

Promise chaining을 사용하면 callback처럼 긴 then지옥에 빠진다


3. Async/Await

  • Promise를 간결하고 동기적으로 처리되는 것처럼 보이게 하기 위함
  • function 앞에 async키워드를 붙이면 해당 함수는 항상 프로미스 객체를 리턴한다
  • await는 async로 선언된 함수 안에서만 사용가능하고, 프로미스가 처리될때까지 기다린다.

Before

class HttpError extends Error {
  constructor(response) {
    super(`${response.status} for ${response.url}`);
    this.name = 'HttpError';
    this.response = response;
  }
}

function loadJson(url) {
  return fetch(url)
    .then(response => {
      if (response.status == 200) {
        return response.json();
      } else {
        throw new HttpError(response);
      }
    })
}

// 유효한 사용자를 찾을 때까지 반복해서 username을 물어봄
function demoGithubUser() {
  let name = prompt("GitHub username을 입력하세요.", "iliakan");

  return loadJson(`https://api.github.com/users/${name}`)
    .then(user => {
      alert(`이름: ${user.name}.`);
      return user;
    })
    .catch(err => {
      if (err instanceof HttpError && err.response.status == 404) {
        alert("일치하는 사용자가 없습니다. 다시 입력해 주세요.");
        return demoGithubUser();
      } else {
        throw err;
      }
    });
}

demoGithubUser();

After

lass HttpError extends Error {
  constructor(response) {
    super(`${response.status} for ${response.url}`);
    this.name = 'HttpError';
    this.response = response;
  }
}

async function loadJson(url) {
  let response = await fetch(url);
  if (response.status == 200) {
    return response.json();
  } else {
    throw new HttpError(response);
  }
}

// 유효한 사용자를 찾을 때까지 반복해서 username을 물어봄
async function demoGithubUser() {

  let user;
  while(true) {
    let name = prompt("GitHub username을 입력하세요.", "iliakan");

    try {
      user = await loadJson(`https://api.github.com/users/${name}`);
      break; // 에러가 없으므로 반복문을 빠져나옵니다.
    } catch(err) {
      if (err instanceof HttpError && err.response.status == 404) {
        // 얼럿 창이 뜬 이후에 반복문은 계속 돕니다.
        alert("일치하는 사용자가 없습니다. 다시 입력해 주세요.");
      } else {
        // 알 수 없는 에러는 다시 던져집니다.
        throw err;
      }
    }
  }


  alert(`이름: ${user.name}.`);
  return user;
}

demoGithubUser();

후기

개인적으로 Async와 Await는 공부를 해도 막상 사용하려고 하면 조금 헷갈린다. 예전에는 보통 디비에서 값을 불러오고 그 값을 사용하려면 async/await을 붙여야한다고 해서 사용했는데 비동기/동기에 대해서 배운 후 부터는 조금씩 이해를 하면서 사용하고있다. 그리고 프로젝트들에서 axios를 자주 썼는데 그때 then을 통해서 불러온 데이터를 저장하거나 사용했는데 그 이유도 axios가 promise기반의 API라서 그랬던것이라니..알고 보니까 신기하고 납득이 이제야 간다..!!!

0개의 댓글