JavaScript 제너레이터: 코드의 'Pause' 버튼

발행: (2025년 12월 2일 오전 08:47 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

Introduction

표준 JavaScript 함수에 익숙하다면 run‑to‑completion 규칙을 알고 있을 것입니다: 일반 함수가 실행을 시작하면 return 문에 도달하거나 코드 블록이 끝날 때까지는 중단될 수 없습니다. 제너레이터는 이 규칙을 깨뜨립니다.

제너레이터는 실행 중간에 일시 정지할 수 있고, 다른 코드를 실행하게 한 뒤, 정확히 멈춘 지점부터 다시 시작하며 모든 변수를 기억합니다. 일반 함수를 끝까지 타야 하는 롤러코스터에 비유한다면, 제너레이터는 넷플릭스 시리즈와 같습니다—잠깐 보고, 일시 정지하고, 다른 일을 한 뒤 같은 지점에서 다시 이어볼 수 있습니다.

Defining a Generator

두 가지 특수 문법이 사용됩니다:

  • function* – 별표(*)는 JavaScript에 이것이 제너레이터임을 알려줍니다.
  • yield – “일시 정지” 버튼.
function* myGenerator() {
  console.log("1. Starting...");
  yield "First Pause"; // Pauses here and outputs "First Pause"

  console.log("2. Resuming...");
  yield "Second Pause"; // Pauses here and outputs "Second Pause"

  console.log("3. Finishing!");
  return "Done";
}

Creating and Running a Generator

제너레이터 함수를 호출한다고 해서 코드가 실행되는 것이 아니라, 제너레이터 객체(이터레이터)를 반환합니다. 이 객체는 리모컨처럼 동작합니다.

const gen = myGenerator(); // No console logs happen here!

실행을 시작하려면 제너레이터 객체에 .next()를 호출합니다. 각 호출은 다음 yield(또는 return)까지 코드를 실행하고 객체를 반환합니다:

  • valueyield 뒤에 오는 값.
  • done – 제너레이터가 계속될 수 있으면 false, 끝났으면 true.
console.log(gen.next());
// Output:
// "1. Starting..."
// { value: "First Pause", done: false }

console.log(gen.next());
// Output:
// "2. Resuming..."
// { value: "Second Pause", done: false }

console.log(gen.next());
// Output:
// "3. Finishing!"
// { value: "Done", done: true }

Sending Data Into a Generator

yield는 데이터를 받을 수도 있습니다. .next(value)를 호출하면 전달된 value가 일시 정지된 yield 표현식의 결과가 됩니다.

function* chattyGenerator() {
  const name = yield "What is your name?";
  const age = yield "How old are you?";
  return `Hello ${name}, you are ${age}!`;
}

const gen2 = chattyGenerator();

console.log(gen2.next().value);          // "What is your name?"
console.log(gen2.next("John").value);    // "How old are you?"
console.log(gen2.next(30).value);        // "Hello John, you are 30!"

Lazy (On‑Demand) Data Generation

제너레이터는 메모리를 소모하지 않고 잠재적으로 무한한 시퀀스를 생성하는 데 이상적입니다.

function* idGenerator() {
  let id = 1;
  while (true) {
    yield id;
    id++;
  }
}

const ids = idGenerator();

console.log(ids.next().value); // 1
console.log(ids.next().value); // 2
console.log(ids.next().value); // 3

Delegating to Another Generator (yield*)

yield*는 제어권을 다른 제너레이터에게 넘겨주어 구성(composition)을 가능하게 합니다.

function* guestDJ() {
  yield "Song A";
  yield "Song B";
}

function* mainDJ() {
  yield "Intro";
  yield* guestDJ(); // Hand over control until guestDJ finishes
  yield "Outro";
}

for (const song of mainDJ()) {
  console.log(song);
}

// Output:
// Intro
// Song A
// Song B
// Outro

Generators and Asynchronous Code

async/await가 등장하기 전, Redux‑Saga 같은 라이브러리는 제너레이터를 사용해 비동기 흐름을 처리했습니다. 제너레이터가 Promiseyield하면, 러너는 해당 프로미스가 해결될 때까지 실행을 일시 정지할 수 있습니다.

function* fetchUser() {
  // Yield the promise; the runner waits for it to resolve.
  const user = yield fetch('/api/user');

  // The resolved value is passed back into the generator.
  console.log(user.name);
}

개념적으로 function*async function과 비슷하고, yieldawait와 같은 역할을 합니다.

Summary – Generator Cheatsheet

SyntaxMeaning
function*제너레이터 함수를 선언
yield value실행을 일시 정지하고 value를 출력
const x = yield일시 정지하고 .next() 로 전달된 데이터를 기다림
generator.next()다음 yield(또는 return)까지 코드를 실행
yield* otherGenerator()다른 제너레이터에 제어권 위임

제너레이터는 코드 흐름을 수동으로 제어할 수 있게 해줍니다. async/await가 간단한 데이터 가져오기에서는 대부분을 대체했지만, 제너레이터는 복잡한 흐름, 무한 데이터 스트림, 상태 머신 구현 등에 여전히 강력한 도구입니다.

Back to Blog

관련 글

더 보기 »

모뎀의 복수

첫 번째 연결 1994년 겨울, 홍콩의 작은 아파트에서, 14세 소년이 US Robotics Sportster 14,400 Fax Modem을 연결했다.

JavaScript 첫 걸음: 간단한 정리

JavaScript에서 변수 let: 나중에 값이 변경될 수 있는 경우에 사용합니다. 예시: ```javascript let age = 20; age = 21; ``` const: 값이 절대로 변경되지 않아야 할 때 사용합니다.