Node.js를 Generators & 콜백과 비교
⚡ 스마트 요약
GeneratorNode.js에서 `yield`는 필요에 따라 실행을 일시 중지하거나 재개할 수 있는 함수입니다. `yield` 키워드는 함수 실행을 일시 중지하고, `next` 메서드는 함수 실행을 재개합니다. 이 둘의 조합을 통해 깊이 중첩된 콜백 함수를 읽기 쉬운 순차적인 코드로 변환할 수 있습니다.

이번 튜토리얼에서는 제너레이터와 콜백의 차이점을 살펴보겠습니다.
발전기란 무엇인가요?
Generators는 인기를 얻게 되었습니다. Node.js를 그들이 할 수 있는 일들 때문에.
- Generators는 일시 중단하고 나중에 다시 시작할 수 있는 함수 실행입니다.
- Generator이는 "지연 실행"과 같은 개념에 유용합니다. 실행을 일시 중단하고 필요할 때 다시 시작함으로써, 값은 필요할 때만 가져옵니다.
Generators는 아래와 같은 두 가지 핵심 방법을 가지고 있습니다.
- 수확량 방법 — 함수 내부에서 호출되어 정확히 해당 줄에서 실행을 중지합니다.
yield나타납니다. - 다음 방법 — 메인 애플리케이션에서 호출되어 실행이 중단된 함수를 재개합니다. 다음 호출이 있을 때까지 실행이 계속됩니다.
yield또는 함수가 종료될 때까지.
제너레이터를 사용하는 예제를 살펴보겠습니다. 이 예제는 두 숫자를 더하는 간단한 덧셈 함수를 정의하고, 제너레이터의 동작 방식을 보여주기 위해 실행을 여러 지점에서 중단합니다.
function* Add(x) { yield x + 1; // The value passed into the second next() call lands here var y = yield(null); return x + y; } var gen = Add(5); gen.next(); // runs to the first yield, returns { value: 6, done: false } gen.next(6); // resumes, y becomes 6, returns { value: 11, done: true }
Code 설명
- 첫 번째 단계는 생성자 함수를 정의하는 것입니다. 다음 사항에 유의하십시오.
*에 추가됨.function키워드입니다. 함수는 다음과 같이 불립니다.Add매개변수를 받습니다.x. - The
yield이 키워드는 제너레이터에 특화되어 있으며 함수 실행 도중에 일시 중지됩니다. 실행은 여기서 멈춥니다.next()호출됩니다. - 두 번째
yield이 함수는 일시 중지되는 동시에 다음 함수에 전달되는 값을 받습니다.next()호출은 값이 됩니다y. - 호출
gen.next()처음 실행 시 함수는 첫 번째까지 실행됩니다.yield. 부름gen.next(6)재개하고 6을 할당합니다.y, 및 반환x + y.
⚠️ 정정: 원래 목록에는 다음 줄이 포함되어 있었습니다. y = 6 직후 var y = yield(null);해당 할당은 기존 값을 덮어씁니다. next() 공급품이 부족해 예시의 목적이 무산되고 두 번째가 잘못되게 됩니다. yield 무의미합니다. 이제 값은 전달됩니다. gen.next(6)이것이 바로 생성기가 호출자로부터 데이터를 실제로 수신하는 방식입니다.
콜백과 제너레이터의 차이점
Generator이 솔루션은 콜백 지옥으로 알려진 문제를 해결합니다. Node.js 애플리케이션 개발 과정에서 콜백 함수가 너무 깊이 중첩되어 이해하기 어려워지는 경우가 있습니다.
이럴 때 제너레이터가 유용합니다. 가장 흔한 예 중 하나는 타이머 함수를 만드는 것입니다. 아래 예제는 간단한 시간 지연 함수를 생성하고 1000ms, 2000ms, 3000ms의 지연 시간으로 해당 함수를 호출합니다.
단계 1) 필요한 시간 지연 코드를 포함하여 콜백 함수를 정의하십시오.
function Timedelay(ptime, callback) { setTimeout(function() { callback("Pausing for " + ptime); }, ptime); // the delay must use ptime, the parameter name }
Code 설명
- 함수라고 불리는
Timedelay매개변수를 사용하여 생성됩니다.ptime여기에는 일시 정지할 밀리초 수를 나타내는 값이 포함됩니다. setTimeout해당 밀리초 동안 기다린 후 제공된 콜백 함수를 호출합니다.
⚠️ 정정: 원래 코드가 통과했습니다 time 두 번째 논거로서 setTimeout하지만 이름이 지정된 변수는 없습니다. time 존재합니다 — 매개변수는 ptime글에 쓰여진 대로라면 그것은 던져진다 ReferenceError: time is not defined.
단계 2) 이제 콜백을 사용하는 코드를 살펴보겠습니다. 1000, 2000, 3000밀리초의 지연을 순차적으로 발생시키려면 콜백 함수들을 서로 중첩시켜야 합니다.
Timedelay(1000, function(message) { console.log(message); Timedelay(2000, function(message) { console.log(message); Timedelay(3000, function(message) { console.log(message); }); }); });
Code 설명
Timedelay이 함수는 1000이라는 값을 가지고 콜백으로 호출됩니다.- 해당 콜백 내부에서,
Timedelay2000으로 다시 호출됩니다. - 그 안에는,
Timedelay3000으로 세 번째 호출됩니다.
⚠️ 정정: 원래 로그에 기록된 각 콜백 msg하지만 매개변수의 이름은 다음과 같습니다. message세 줄 모두 던졌습니다. ReferenceError: msg is not defined.
위 코드에서 볼 수 있듯이 호출이 추가될 때마다 코드가 점점 더 복잡해지는데, 이러한 중첩 구조가 바로 콜백 지옥(callback hell)을 의미합니다.
단계 3) 이제 제너레이터를 사용하여 동일한 동작을 살펴보세요. 이 시퀀스는 세 단계의 중첩 구조가 아니라 세 개의 평평한 선으로 표시됩니다.
function* Messages() { console.log(yield Timedelay(1000)); console.log(yield Timedelay(2000)); console.log(yield Timedelay(3000)); }
Code 설명
- 제너레이터 함수가 정의되어 호출됩니다.
Timedelay기능. yield와 함께 사용됩니다Timedelay매개변수 값은 1000입니다.yield2000과 함께 다시 사용되고, 3000과 함께 한 번 더 사용됩니다.
⚠️ 정정: 원문에는 이렇게 쓰여 있습니다. console,log(...) 세 줄 모두에 점 대신 쉼표가 사용되어 구문 오류가 발생했으며, 이로 인해 파일 구문 분석이 전혀 이루어지지 않습니다.
실행 방법 Generator 러너 기능 포함
위의 생성기는 보기에는 아름답지만, 그 자체로는 아무런 동작도 하지 않습니다. 대부분의 설명에서 생략되는 부분이 바로 이 점이며, 평면 버전이 마법처럼 보이는 이유이기도 합니다. 생성기는 일시 정지된 기계와 같아서, 무언가가 계속해서 버튼을 누르고 있어야 합니다. 즉, 호출해야 한다는 것입니다. Messages() 단순히 제너레이터 객체를 생성하고 즉시 반환할 뿐이며, 타이머는 시작되지 않고 아무것도 출력되지 않습니다.
빠진 부분은 실행기, 즉 호출하는 작은 함수입니다. next()비동기 작업이 완료될 때까지 기다린 후 호출합니다. next() 다시 결과를 알려드리겠습니다.
// Timedelay now hands its result back to the runner function Timedelay(ptime) { return function(resume) { setTimeout(function() { resume("Pausing for " + ptime); }, ptime); }; } // The runner drives the generator to completion function run(generatorFunction) { var it = generatorFunction(); function step(value) { var result = it.next(value); if (result.done) return; // result.value is the function returned by Timedelay result.value(step); } step(); } run(Messages);
이것이 효과적인 이유는 세 가지입니다. 첫째, Timedelay 더 이상 콜백을 직접 받지 않고, 타이머가 작동할 때 제어권을 반환하는 실행기가 호출할 수 있는 함수를 반환합니다. 둘째, it.next(value) 이전 결과를 일시 중지된 생성기에 입력하는데, 이것이 바로 가능한 이유입니다. yield 과제의 오른쪽에 나타나도록. 세 번째로, 주자는 즉시 멈춘다. result.done 조건이 참이 되므로 재귀가 자연스럽게 종료됩니다. 이러한 실행 패턴은 co와 같은 라이브러리에서 제공하는 것과 정확히 일치하며, 바로 이러한 메커니즘을 사용합니다. async/await 나중에 언어 자체에 흡수되었다.
Generator`s`와 `async/await` 중 어떤 것을 사용해야 할까요?
Generator이전에는 비동기 코드를 작성하는 표준적인 방법이었습니다. async/await 이미 존재했고, 두 가지 모두 함수 실행 도중 일시 중지한다는 기본적인 아이디어를 공유합니다. Node는 이를 지원해 왔습니다. async/await 버전 7.6부터 기본적으로 지원되므로 오늘부터 새로운 업무를 시작하는 모든 사용자에게 권장 사항이 변경되었습니다.
| 아래 | Generators | 비동기/대기 |
|---|---|---|
| 달리기 선수 모집 | 네, 본인이 쓰셨거나 도서관에서 쓰신 것입니다. | 아니요, 언어 자체에 내장되어 있습니다. |
| 일시 중지 키워드 | yield |
await |
| 오류 처리 | 주자는 오류를 전달해야 합니다 | 일반적인 시도 및 잡기 |
| 중간에 멈출 수 있습니다 | 네, 그리고 선택적으로 재개할 수 있습니다. | 아니요, 완료될 때까지 실행됩니다. |
| 가장 좋은 | 지연 시퀀스와 무한 스트림 | 일반적인 비동기 작업 |
async/await 새로운 코드에서 비동기 흐름을 구현할 때는 `try` 문을 제거하고 일반적인 `try-catch` 구문을 복원하는 것이 좋습니다. 제너레이터는 값을 지연 평가하거나, 크거나 무한한 시퀀스를 순회하거나, 소비자가 다음 값 계산 시점을 정확히 결정해야 하는 경우와 같이 제너레이터가 잘 수행하는 경우에만 사용해야 합니다.
공통의 Generator 오류 및 해결 방법
제너레이터 관련 문제의 대부분은 함수가 호출되기 전까지는 비활성 상태라는 사실을 잊어버리는 데서 발생합니다. 함수 호출 오류는 대부분 함수가 호출되기 전까지는 비활성 상태라는 점을 간과하는 데서 비롯됩니다. next()또는 별표 주변의 작은 구문 오류로 인해 발생할 수 있습니다. 아래 각 증상에는 원인과 해결 방법이 명시되어 있습니다.
- 제너레이터를 호출해도 아무 일도 일어나지 않습니다. 이 함수를 호출하면 결과가 아닌 이터레이터가 반환됩니다.
next()또는 달리는 사람에게 전달하세요. - yield에 대한 SyntaxError: 별표가 빠져 있습니다.
yield내부에서만 유효합니다.function*. - next()에서 전달된 값이 undefined로 도착합니다. 첫번째
next()생성기가 아직 도달하지 않았기 때문에 호출이 값을 전달할 수 없습니다.yield아직입니다. 두 번째 통화부터 데이터를 전송하세요. - 달리기 게임에서 무한 루프에 빠지는 현상:
result.done절대 확인되지 않으므로next()종료 시간을 지나 계속 호출됩니다. 완료되면 항상 반환해야 한다는 것은 사실입니다. - 오류는 조용히 사라집니다. 비동기 단계 내에서 발생하는 거부는 생성기로 다시 전달되지 않습니다. 따라서 해당 거부를 전달해야 합니다.
it.throw(err)그렇게 하면 생성기 내부에 작성된 try-catch 구문이 실제로 해당 오류를 인식하고 처리할 수 있습니다.




