2 minute read

자바스크립트의 이벤트 루프에 대해 알아보다가 결국 비동기까지 알아보게 되었다.
자바스크립트는 싱글 스레드 언어이다. 이것은 싱글 callStack을 가지고 있다는 의미로 해석되는데 이는 자바스크립트 엔진의 특성이기도 하다. 싱글 스레드라는 것은 어떻게 동작한다는 것일까?

동기와 비동기

콜스택이 하나밖에 없는 자바스크립트는 한번에 하나의 task만 수행 가능하다. 즉, 동기적으로 일을 수행한다. 하나의 task를 수행하면 다른 task는 대기 상태가 된다. 만약 진행하고 있는 task를 수행하는데 5초가 걸려도 남은 것들은 무작정 대기 상태가 되어버린다. 단점밖에 없어보이지만 로직 자체가 직관적이라는 장점이 있다.
그렇다면 비동기는? 진행중인 task가 5초가 걸린다면 다른 task를 함께 수행한다. 동시성이 존재한다고 하는데 이는 자원을 효율적으로 사용할 수 있다는 장점이 있다. 하지만 동기적으로 작동하는 것 보다 복잡하다는 단점이,,


비동기적으로 동작해야할 때

사실 자바스크립트는 모두 동기적으로 동작하며 특정 메서드 등을 사용하면 비동기적으로 실행할 수 있게 해준다고 생각하고 있었다. (와이,,!)
근데 그게 아니었다. 자바스크립트에서도 비동기로 동작하는 것들이 있었다. 대표적으로 setTimeout, ajax 등등. 이제, 생각해볼것이 비동기의 단점이다. 비동기는 동시성을 제공하기 때문에 동기적으로 task를 수행할 때 타이밍을 예측하기 어려울 것이다. 그래서! callback, promise, async & await가 나온것이다! 비동기 작업에서 가장 어려운 것은 비동기적인 task의 수행이 끝나고 어떤 task가 수행될 것인다! 를 예측하는 것.


Callback

예를 들어 이미지를 처리하는 동작이 있다고 치자, 이미지를 처리한 후에 이미지를 사용하는 코드를 불러올 수 있을 것이다. (이미지 처리가 선행되어야 하는 코드) 이미지 처리는 비동기적으로 작동하고 사용하는 코드는 동기적으로 작동한다고 했을때 문제가 발생한다. 이미지가 없다는 것!!! 타입에러가 발생할 것이다. 그렇다면 나는 이미지를 처리 한 후에 사용하는 코드를 실행하고 싶다.
이때 콜백 함수를 사용할 수 있다. 이미지 처리부분에 콜백함수로 이미지 사용 코드를 실행하는 것이다! (비동기 작업을 스케줄링 하는 것이다!) 하지만 콜백함수를 사용하여 비동기 로직을 처리할 경우 콜백 외부에서는 어떤 값이 오는지 알 수 없다. 또한 콜백을 연속적으로 사용하게 된다면 콜백 지옥을 발생 시킬 수 있다.
(자주 보이는 그림…)

스크린샷 2023-01-03 오후 3 37 15


Promise

그럼 콜백함수를 사용하면서 어떤 값을 오는지 알 수 있는 방법은 무엇이 있을까! 바로바로 프로미스를 사용하면 된다. 프로미스는 콜백함수로 resolve, reject를 제공하며 성공시 resolve를 실패시 reject를 호출하게 된다. 이것은 상태까지 확인할 수 있다. 프로미스 객체가 생성되면 pending → 호출 결과가 성공하면 fulfilled → 실패하면 reject의 상태를 가지게 된다.

let promise = new Promise(function(resolve, reject) {
 
});

promise.then(
  function(result) { /* 결과(result)를 다룹니다 */ },
  function(error) { /* 에러(error)를 다룹니다 */ }
);

  • resolve(value) — 일이 성공적으로 끝난 경우 그 결과를 나타내는 value와 함께 호출
  • reject(error) — 에러 발생 시 에러 객체를 나타내는 error와 함께 호출 이것으로 비동기 작업에 스케줄링을 간단하게, 또한 비동기 작업의 실행 결과를 파악하기 좀 더 간단해졌다. 하지만 프로미즈 같은 경우 객체를 생성하고 then 체이닝으로 작업을 수행할 수 있게 되는데 우선 비동기 작업을 처리하는데 가독성이 떨어지고 then 체이닝도 사용을 남발하게 되면 유지보수도 어려울 것이다. 그래서 나온것은 async, await!


async, await

function 앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환한다. 프라미스가 아닌 값을 반환하더라도 이행 상태의 프라미스(resolved promise)로 값을 감싸 이행된 프라미스가 반환되도록 한다. 또한 비동기 함수의 실행을 동기적으로 보이게 하며 가독성을 높여준다는 장점을 가지고 있고, try-catch 문과 함께 사용하면 에러에 대한 처리도 간단해진다.

await는 말 그대로 프라미스가 처리될 때까지 함수 실행을 기다리게 만듭니다. 프라미스가 처리되면 그 결과와 함께 실행이 재개되죠. 프라미스가 처리되길 기다리는 동안엔 엔진이 다른 일(다른 스크립트를 실행, 이벤트 처리 등)을 할 수 있기 때문에, CPU 리소스가 낭비되지 않습니다. await는 promise.then보다 좀 더 세련되게 프라미스의 result 값을 얻을 수 있도록 해주는 문법입니다. promise.then보다 가독성 좋고 쓰기도 쉽습니다.

라고 한다.
이벤트 루프에 대해 공부하다가 비동기까지 파고 들어갈 줄이야.. 전부 연관이 되어있어서 도장깨기 식으로 이해하는 중이다. 기본이 중요하다는 것을 다시한번 느끼면써…



Updated: