동기 비동기 차이 이해하기

동기 비동기 차이점을 이해하기까지 험난했던 과정을 공유하기 위해 이 글을 작성했다. 이 글을 참고하여 내가 겪었던 시행착오를 여러분들은 겪지 않기를 바란다. 🙏

비동기와의 첫 만남

Java, C++을 사용하다가 자바스크립트를 처음 사용해봤을 때 강렬한 경험을 했다. 분명히 함수를 호출하고 나면 결과를 받아오고 나서 다음 줄의 코드를 순차적으로 실행해야 하는데 코드가 순서대로 동작하지 않는 것이다. 깜짝 놀라서 인터넷 검색을 시작했다. 그 과정에서 Web API, 콜백 함수, 동기/비동기 개념, Promise, Async/Await 등의 존재를 알게 되었다. 웹 사이트 이곳 저곳을 돌아다니며 배운 내용으로 프로젝트에 적용해보려 했으나 실패하곤 했다. 동기/비동기 그놈이 뭐길래 나를 이렇게 힘들게 하는지.. 😥 분명히 내가 모르고 있는 게 있다.

내가 모르는 게 뭔지 모르겠다

현업에서 자바스크립트를 주 언어로 사용하고 있는 학교 후배에게 도움을 요청했다. “어느 정도 이해는 했는데 뭔가 부족하다. 내가 모르고 있는 게 있는 것 같다. 동기/비동기를 정확히 이해하기 위해서 무엇을 아는 게 중요하냐”고 물어봤는데, ‘자바스크립트 런타임’ 에 대해 검색해보라는 대답을 들었다. 자바스크립트가 어떤 환경에서 실행되고 있는지 살펴 보라는 것이다. 그리고 힌트를 얻기 위하여 “비동기 함수의 동작 방식에 대해서 주관적으로 이해한 대로 한마디로 표현해 줄 수 있느냐”고 했더니 ‘V8 엔진에게 일을 던져주고 내 할 일을 계속 하다가 V8 엔진이 결과물을 던져주면 그걸 받아서 다시 하는 것’ 이라고 했다. 나는 똥인지 된장인지 찍어 먹어보면서 천천히 음미하는 타입이다.(?!) 나는 삽질을 시작했다. 😤

삽질하기

삽질하기
삽질하는 타깃코더

내가 비동기 프로그래밍을 처음 만났을 때 이해가 잘 되지 않은 이유는 동기적 프로그래밍에 익숙해져 있었기 때문이다. 즉 머리가 당연하게 생각하고 있던 상식을 깨뜨려야 하는 상황에 놓인 것이다. 프로그램을 실행했을 때 내가 예상한 결과와 다른 결과가 나온다. 그래서 내가 선택한 해결 방안은 왜 내가 예상한 결과가 나오지 않는 것인지 계속해서 결과를 예측하면서 이유를 파악해 보고(가설 세우고 확인하기), 내 뇌가 비동기 프로그램의 실행 결과를 예측할 수 있도록 만드는 것이다.

Promise 객체를 사용하면 비동기적인 작업을 동기적으로 할 수 있게 되는가?

혼란스러웠던 부분 1.
setTimeout 함수가 비동기적으로 수행되는 함수이고, 이를 Promise 함수에 넘기면 setTimeout 함수를 동기적으로 처리할 수 있게 된다는 말로 이해했다.

const promiseTest = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Success");
      resolve();
    }, 2000);
  });
};
 
console.log("1");
promiseTest();
console.log("2");
console.log("3");
console.log("4");

위 코드를 보고 결과를 한 번 예상해보길 바란다.

[예상 결과]
1
Success
2
3
4

[실제 결과]
1
2
3
4
Success

내 예상은 틀렸다. 그러면 Promise 객체를 어떻게 사용하라는 거지? 어떤 일이 끝날 때 까지 기다렸다가 다음에 할 일을 정해줄 수 있다고 하던데, 그럼 어떻게 하라는 말인가? 검색과 삽질을 반복하면서 아래와 같은 코드를 작성해보았다.

const promiseTest = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Success");
    }, 2000);
  });
};
console.log("1");
promiseTest().then((ret) => {
  console.log(ret);
  console.log("2");
  console.log("3");
  console.log("4");
});

이렇게 하면 처음에 예상했던 결과가 나온다. 2초를 기다린 뒤에 then 내부의 코드가 실행된다. resolve 함수 인자로 “Success”를 넣어주면 then 메서드의 매개변수 ret로 받아서 사용할 수 있다. 이런 걸 프라미스 체인이라고 한다.

Promise 객체를 사용할 때 어느 부분이 동기적으로 처리되는가?

혼란스러웠던 부분 2.
코드의 어느 부분이 동기적으로 실행되고 어느 부분이 비동기적으로 실행되는 건지 혼란스러웠다. 이를 확인해보기 위해 아래와 같은 코드를 작성했다.

const promiseTest = () => {
  console.log("2");
  console.log("3");
  console.log("4");
  return new Promise((resolve, reject) => {
    console.log("5");
    console.log("6");
    console.log("7");
    setTimeout(() => {
      console.log("8");
      console.log("9");
      console.log("10");
      resolve("Success");
    }, 2000);
  });
};
console.log("1");
promiseTest().then((ret) => {
  console.log(ret);
  console.log("11");
  console.log("12");
  console.log("13");
});
console.log("14");
console.log("15");
console.log("16");

위 코드를 보고 결과를 한 번 예상해보길 바란다.

[예상 결과]
1
2
3
4
14
15
16
5
6
7
8
9
10
Success
11
12
13

[실제 결과]
1
2
3
4
5
6
7
14
15
16
8
9
10
Success
11
12
13

이런 삽질을 통해서 Promise 객체를 이해하고 이를 활용한 비동기 코드를 내 프로젝트에 적용해볼 수 있게 되었다. 내가 얻은 이해를 바탕으로 동기와 비동기의 차이점을 쉽게 나타내보았다.

동기 비동기 차이점

한마디로 쉽게 설명하면 동기 프로그램은 처음부터 끝까지 혼자서 순차적으로 일을 처리하는 프로그램을 말하고, 비동기 프로그램은 내가 일을 하다가 시간이 좀 걸리는 일을 친구한테 넘겨주고서 바로 다음 일을 처리하는 프로그램이다.

이해를 돕기 위해 ‘집에 들어와서 손 씻고 저녁 먹기’, ‘PC를 부팅하고 메일 확인하기’ 크게 두 가지 일을 하는 프로그램을 작성해봤다.

동기 비동기 차이점 이해하기
동기 프로그램

동기적인 프로그램은 나 혼자서 PC가 부팅 완료된 것을 확인하고 화장실로 가서 손을 씻고 메일을 확인한 다음 저녁을 먹는다.

동기 비동기 차이점 이해하기
비동기 프로그램

위 프로그램은 메일을 확인하는 일을 친구에게 시켜서 비동기적으로 수행하고 있다. 나는 집에 들어와 신발을 벗고, PC의 전원 버튼을 누른 뒤에 화장실에서 손을 씻고 밥을 먹는다. 내 친구는 PC를 부팅하고 부팅이 완료되면 메일을 확인한다. 메일 확인하는 일을 친구에게 넘겨 비동기적으로 처리한 것이다. 부팅이 될 때까지 기다리고 서있을 필요 없이 나는 다음 일을 계속 처리할 수 있다.

여러분이 동기 비동기 차이점을 이해하는 데 조금이나마 도움이 되었길 바라며 이 글을 마친다.

스스로 경험하며 얻은 깨달음을 공유하기 좋아하며, 세상이 필요로 하는 코드를 작성하기 위해 노력하는 개발자입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다