Frontend

<Frontend> JavaScript / 동기/비동기

이게왜 2024. 4. 2. 16:16

Block / NonBlock , Sync / Async

이번에는 JS에서 가장 중요하면서 어렵고 헷갈리는 개념 중 하나인 "Block / Non - Block", "Sync / Async"를 알아보겠습니다!

머리로는 이해해도 설명해보라고 하면 뭐라 설명할 수 없는 그런....

저도 100% 이해가 어려워 계속해서 코드를 작성해 보며 이해해 나가고 있습니다.

파이팅!!


Block / NonBlock

Block

  • 현재 작업이 다른 작업을 실행을 차단하는가
  • 제어권을 기준으로 함.

const fs = require('fs');

const data = fs.readFileSync('./file_path');

console.log('파일 읽기 완료', data);

// data에 파일이 읽힌 후, '파일 읽기 완료'가 출력된다.
  • 특정 작업을 실행할 때 제어권을 완전히 넘기는 방식
  • 제어권이 넘어갔기 때문에, 다른 작업을 진행할 수 없음

Non Block

  • 특정 작업 실행 시 제어권을 넘겨 실행 후 즉시 돌려받는 형태
  • 작업이 진행되는 동안 백그라운드에서 다른 작업이 진행
  • 제어권을 돌려받기 때문에 다른 작업을 수행할 수 있음
  •  


Sync / Async

  • 현재 작업과 다음 작업이 순서 대로 실행 되는가?
  • 결과를 기준으로 함.

Sync

  • 특정 작업이 완료될 때까지 기다리는 방식
  • 제어권은 특정 작업 실행 이후 즉시 돌려받는 형태.
  • 사실상 제어권이 넘어오면서 결과도 같이 나온다.(Block / Async)

즉, 제어권은 즉시 돌려받지만 작업이 완료되어 결과가 나올 때까지 다른 작업을 수행하지 않음.

function doWorkSync() {
    const start = Date.now();
    while (Date.now() < start + 10000); 
    console.log('동기 작업 완료');
}

console.log('작업 시작');
doWorkSync();
console.log('다음 작업');

//작업 시작
//현재시간 + 10초간 '동기 작업 완료'가 계속 출력됨.
//다음 작업

이 처럼 doWorkSync()가 끝날 때 까지 기다린 후 console.log(’다음 작업’) 이 실행됩니다.


Async

  • 특정 작업에 대한 진행 상황, 결과 처리를 제어권이 신경 쓰지 않음.
  • 비동기 직업 이후 결과 처리를 해야 한다면?
    • 기존 작업 진행하고 있는 게 있다면 처리 후 진행

function doWorkAsync() {
    setTimeout(() => {
        console.log('비동기 작업 완료');
    }, 1000); 
}

console.log('작업 시작');
doWorkAsync(); //작업이 끝나고 결과가 나왔어도 call stack이 비어있지 않아서 기다림(call stack이 완전히 비어있을 때 결과 출력)
console.log('다음 작업');

//작업 시작
//다음 작업
//비동기 작업 완료

 


 

Combination

  Block Non - Block
Sync Block / Sync Non - Block / Sync
Async Block / Async Non - Block / Async

Block / Sync

  • 제어권과 결과 처리 순서가 동일한 방식.

Non - Block / Sync

  • 제어권은 실행 즉시 반환
  • 지속적인 결과처리 관찰
  • 결과가 완료되었을 때 해당 처리 진행 (call stack이 비어있는 경우)

Block / Async

  • 제어권은 실행 즉시 반환
  • 결과 처리가 나올 때까지 다른 작업을 하지 않음 (Sync 작업과 같음)
  • 잘못된 코딩의 예시이다

Non-Block / Async

  • 실행 즉시 제어권 반환
  • 결과에 관계없이 자신의 작업 진행
  • 결과처리를 요청받으면 현재 작업을 마무리하고 결과 처리 작업 진행

Excution Context와 비동기 처리

  1. call stack에 비동기 setTimeout() context push
  2. WebAPI에게 setTimeout context 전달
    1. 비동기 작업 진행(1초 대기)
  3. Func b context가 call stack에 push 후 진행
  4. Func c context가 call stack에 push 후 진행
  5. WebAPI가 1초가 지난 후 setTimeout context를 TaskQueue로 전달
  6. EventLoop가 call stack과 TaskQueue를 지속적으로 감시하며 call stack이 비어있을 때, TaskQueue에 있는 setTimeout context를 call stack으로 전달
  7. setTimeout context call stack에 push후 진행
const a = () => {
  console.log("a");
  return d();
};

const b = () => {
  console.log("b");
};

const c = () => {
  setTimeout(() => {
    console.log("c");
  }, 1000);
};

const d = () => {
  setTimeout(() => {
    console.log("d");
  }, 0);
};

c();
a();
b();

//출력
//a
//b
//d
//c