JS 5.1 · 5부. 비동기 프로그래밍

동기와 비동기

먼저 작성한 코드가 늘 먼저 끝나지는 않는다는 것을 봅니다.

예상 학습 시간 14분 실행 단추가 있는 예제는 고쳐서 실행해 볼 수 있습니다 난이도 초급
개념 설명

먼저 적은 것이 먼저 끝나지 않습니다

여기까지의 코드는 위에서 아래로 차례대로 실행됐습니다. 한 줄이 끝나야 다음 줄이 시작합니다. 이것을 동기(synchronous) 라고 합니다.

그런데 서버에서 데이터를 가져오는 일은 오래 걸립니다. 그동안 아무것도 못 하고 멈춰 있으면 화면이 얼어붙습니다. 그래서 오래 걸리는 일은 맡겨 두고 다음 줄을 먼저 실행합니다. 이것이 비동기(asynchronous) 입니다.

최소 예제 · 편집 가능

차례를 예측해 보세요

실행하기 전에 어떤 차례로 나올지 먼저 생각해 보세요.

script.js
console.log("첫째");

setTimeout(() => {
	console.log("셋째");
}, 1000);

console.log("둘째");
출력
첫째 둘째 셋째

setTimeout나중에 할 일을 맡겨 두는 함수입니다. 첫 인자가 할 일(함수), 둘째가 기다릴 밀리초입니다. 맡기고 나서 바로 다음 줄로 넘어갑니다.

상세 사용법

0밀리초여도 마지막입니다

script.js
console.log("첫째");

setTimeout(() => console.log("셋째"), 0);

console.log("둘째");
출력
첫째 둘째 셋째

0 을 적어도 지금 실행 중인 코드가 모두 끝난 뒤에 실행됩니다. 맡긴 일은 줄을 서서 기다리고, 지금 하던 일이 끝나야 차례가 옵니다.

그래서 setTimeout 의 시간은 정확히 그때가 아니라 그때 이후 가장 빠른 때 입니다.

상세 사용법

여러 개를 맡기면

script.js
setTimeout(() => console.log("300"), 300);
setTimeout(() => console.log("100"), 100);
setTimeout(() => console.log("200"), 200);

console.log("먼저");
출력
먼저 100 200 300

적은 차례가 아니라 시간이 짧은 것부터 나옵니다. 맡긴 일들은 서로 기다리지 않습니다.

상세 사용법

동기 코드는 화면을 멈춥니다

아래처럼 오래 도는 반복문은 그동안 아무것도 못 하게 만듭니다. 버튼도 눌리지 않고 화면도 그려지지 않습니다.

이렇게 하지 않습니다
const end = Date.now() + 3000;

while (Date.now() < end) {
	// 3초 동안 화면이 멈춥니다
}

console.log("끝");

이 예제에는 실행 단추가 없습니다. 실행하면 3초 동안 아무것도 하지 못하고, 이 화면의 실행기는 그것을 무한 루프로 보아 중단합니다(1.10).

서버 요청도 이만큼 오래 걸립니다. 그것을 동기로 기다렸다면 요청할 때마다 화면이 얼어붙었을 것입니다. 비동기가 필요한 까닭이 이것입니다.

상세 사용법

맡긴 일 취소하기

script.js
const cancelled = setTimeout(() => console.log("이 줄은 나오지 않습니다"), 100);

clearTimeout(cancelled);

const kept = setTimeout(() => console.log("이 줄만 나옵니다"), 200);
출력
이 줄만 나옵니다

setTimeout 은 번호를 돌려줍니다. 그 번호로 clearTimeout 을 부르면 맡긴 일이 취소됩니다.

흔한 실수

처음에 자주 걸리는 것

1. 맡긴 일의 결과를 바로 아래에서 읽습니다

아직 실행되지 않았으므로 값이 없습니다. 이것이 비동기에서 가장 많이 하는 실수이고, 5.3 부터 그것을 다루는 방법을 배웁니다.

let result;
setTimeout(() => { result = "값"; }, 100);
console.log(result);   // undefined 입니다
2. 함수에 괄호를 붙여 넘깁니다

2.6 · 4.5 에서 본 것과 같습니다. 괄호를 붙이면 그 자리에서 실행됩니다.

setTimeout(hello(), 100);   // 지금 실행됩니다
setTimeout(hello, 100);     // 이렇게 적습니다
3. 시간을 정확한 약속으로 압니다

100 은 "100밀리초 뒤" 가 아니라 "100밀리초 뒤부터 가능한 때" 입니다. 앞의 코드가 오래 돌면 더 늦어집니다.

실습 문제

직접 해보기

1. 차례 예측하기 난이도 하

아래 코드의 출력 차례를 먼저 적어 보고, 편집기에 넣어 확인하세요.

console.log("A"); setTimeout(() => console.log("B"), 0); console.log("C"); setTimeout(() => console.log("D"), 0); console.log("E");
A C E B D
2. 1초마다 세기 난이도 중

0.2초 간격으로 1 부터 3 까지 출력하세요. 반복문 안에서 setTimeout 을 사용하면 됩니다.

기다릴 시간을 i 에 따라 다르게 주면 됩니다.
for (let i = 1; i <= 3; i++) { setTimeout(() => console.log(i), i * 200); }
요약

이 단원의 정리

  • 오래 걸리는 일은 맡겨 두고 다음 줄을 먼저 실행합니다.
  • setTimeout 은 나중에 할 일을 맡깁니다.
  • 시간이 0 이어도 지금 코드가 끝난 뒤에 실행됩니다.
  • 맡긴 일들은 서로 기다리지 않고, 시간이 짧은 것부터 나옵니다.
  • 맡긴 일의 결과를 바로 아래에서 읽을 수 없습니다. 5.3 부터 그 방법을 배웁니다.