Search
Duplicate
🎮

Js의 비동기

간단소개
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
JS
Scrap
태그
9 more properties

1. 동기? 비동기?

동기(synchronous)작업은 작업이 순차적으로 이뤄지는 일괄작업을 의미하고 비동기(asynchonous)작업은 작업이 현재 상태와 관계없이 이뤄진다. 커피숍을 예시로 들면 커피를 한명씩 순서대로 대기하여 받아가면 동기 작업이고 진동벨을 통해 비 순차적으로 받아가면 비동기 작업이다.

2. 블로킹, 논 블로킹

동기작업은 하나의 작업을 수행하면 다른 작업은 수행되지 않고 대기한다. 이를 블로킹(blocking)이라 한다. 반면 비동기 작업은 현 상태와 관계없으므로 작업들이 병렬적으로 수행된다. 이를 (non blocking)이라고 한다.

3. Js에서의 비동기

알 사람들은 알고 있듯이 js는 브라우저나 node v8에서 기본적으로 싱글스레드언어이다. 싱글스레드는 기본적으로 별도의 스레드에 임무을 할당할 수 없으므로 비동기 작업을 독특한 방식으로 실행한다. 그 첫번째가 web worker 이다.

4. Web worker

웹 워커(web worker)는 브라우저에서는 새로운 스레드를 생성하여 논 블로킹작업을 수행하고 node에선 worker thread를 생성하여 비동기 작업을 수행한다.
const worker = new Worker('worker_file.js') worker.onmessage = (e) => { ... } worker.terminate() /* worker_file.js */ const some_data_object = some_work() postMessage(some_data_object)
JavaScript
복사
브라우저에선 worker를 생성하고 onmessage 를 통해서 worker가 보낸 데이터를 받는다. worker는 작업을 수행하고 postMessage 를 통해 데이터를 보낸다. 작업이 마무리된 worker는 종료(terminate) 시켜야 한다.
Worker는 상당히 효율적인 방식이지만 근본적인 2가지 문제가 존재한다. 하나는 Dom에 접근하지 못하는 점이고 하나는 메인 프로세스에서 결과를 받아서 진행하는것이 어렵다는 점이다. 따라서 새로운 접근법이 요구되었고 그게 asynchronous code이다

5. Asynchronous code

비동기 방식을 스레드내에서 이벤트루프(event loop)로 처리하는 방식이 비동기 코드(Asynchronous code)이다. 먼저 이벤트 루프부터 살펴본다.

5 - 1. 이벤트 루프

브라우저를 기준으로 설명하면 브라우저는 콜 스택(Call Stack)에 실행될 코드를 쌓아둔다. 이때 비동기로 실행된 코드는 콜 스택이 아니라 태스크 큐(Task Queue)에 보관이 된다. 이벤트 루프는 2개의 상태를 체크하여 콜 스택이 비어있으면 태스크 큐의 작업을 하나씩 콜스택으로 밀어넣는다.

5 - 2. 콜백

해당 함수가 실행된 후 동작하는 함수를 callback이라 지칭하며 해당 함수들을 비동기적으로 구현하는 대표적인 예가 setTimeout`이다.
const log = () => console.log('log') setTimout(log, 1000}
JavaScript
복사
위 코드의 log는 1초 후에 실행되게 되는데 내부적 동작을 살펴보면 setTimeout은 webAPI에서 1초의 대기시간을 거친 후 태스크 큐에 해당 작업을 추가한다. 이벤트 루프는 콜 스택이 비어있으므로 log를 콜 스택에 추가하고 함수를 실행한다. 여기서 재미있는 것은 아래 코드를 실행시켰을 때의 결과이다.
const startLog = () => console.log('start') const loopLog = () => console.log('loop') const endLog = () => console.log('end') setTimeout(satrtLog, 0) for (let i = 0; i < 100000; i++) loopLog() endLog()
JavaScript
복사
위 코드의 결과를 안다면 이미 이벤트 루프를 이해하고 있는 것이다. 결과를 보면 start가 제일 마지막에 찍히는 것을 확인 할 수 있을 것이다. loopLog가 아무리 오래 걸리더라도 setTimeout으로 실행시킨 startLog가 가장 마지막에 실행된다. 이벤트 루프는 콜스택이 비어있을 때만 태스크큐의 동작을 콜백으로 밀어넣기 때문이다.
더 자세한 내용이나 시뮬레이션이 궁금하다면 아래 사이트를 참고하자

5 - 3. 프로미스

콜백은 상당히 유용하지만 콜백 지옥(callback hell)에 빠질 위험이 크다. 콜백 지옥이 궁금하다면 아래 글을 참고하자.
그래서 ES6기준으로 비동기 처리 방식을 프로미스(Promise)로 표준화 하였다. 프로미스는 어떤 연산의 결과를 연속적으로 이어받아 처리할 수 있는 체인(Chain)으로 비동기 작업의 미래를 표시합니다. 프로미스는 기본적으로 then을 통해 해당 작업의 결과를 반영한 작업을 할 수 있으며 콜백지옥을 벗어나는 표준적인 방법이다.
자세한 내용은 MDN을 참고하자

5 - 4. 기타

Generator나 async/awit와 Promise를 함께 사용하는 등 다양한 방식으로 비동기 코드를 처리할 수 있다. 다만 해당 내용은 이 글의 주제를 벗어나니 궁금하다면 MDN을 참고하자.