Node.js를 Generators & 콜백과 비교

⚡ 스마트 요약

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

  • ⏸️ 핵심 행동: 제너레이터는 각 yield 호출 시 실행을 일시 중단하고, next가 호출될 때 중단된 지점에서 정확히 다시 실행을 시작합니다.
  • ✳️ 선언: 함수 키워드 뒤에 별표(*)가 붙으면 해당 함수는 일반 함수가 아닌 제너레이터 함수임을 나타냅니다.
  • 🔄 양방향 채널: `next`에 전달된 값은 함수 실행을 일시 중지시킨 `yield` 표현식의 결과가 됩니다.
  • 🪆 콜백 지옥: 중첩된 콜백 함수는 단계가 추가될수록 가독성이 떨어지는데, 이것이 바로 문제 해결을 위해 제너레이터가 도입된 이유입니다.
  • 🏃 달리기 선수 필요: 제너레이터는 자체적으로 실행되지 않습니다. 비동기 작업이 진행되려면 러너 함수가 next를 반복적으로 호출해야 합니다.
  • 🦥 지연 실행: 일시 중단 및 재개 기능을 사용하면 프로그램이 필요한 순간에만 값을 가져올 수 있습니다.

Node.js를 Generator콜백과 비교

이번 튜토리얼에서는 제너레이터와 콜백의 차이점을 살펴보겠습니다.

발전기란 무엇인가요?

Generators는 인기를 얻게 되었습니다. Node.js를 그들이 할 수 있는 일들 때문에.

  • Generators는 일시 중단하고 나중에 다시 시작할 수 있는 함수 실행입니다.
  • Generator이는 "지연 실행"과 같은 개념에 유용합니다. 실행을 일시 중단하고 필요할 때 다시 시작함으로써, 값은 필요할 때만 가져옵니다.

Generators는 아래와 같은 두 가지 핵심 방법을 가지고 있습니다.

  1. 수확량 방법 — 함수 내부에서 호출되어 정확히 해당 줄에서 실행을 중지합니다. yield 나타납니다.
  2. 다음 방법 — 메인 애플리케이션에서 호출되어 실행이 중단된 함수를 재개합니다. 다음 호출이 있을 때까지 실행이 계속됩니다. yield또는 함수가 종료될 때까지.

제너레이터를 사용하는 예제를 살펴보겠습니다. 이 예제는 두 숫자를 더하는 간단한 덧셈 함수를 정의하고, 제너레이터의 동작 방식을 보여주기 위해 실행을 여러 지점에서 중단합니다.

Node.js를 Generators

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 설명

  1. 첫 번째 단계는 생성자 함수를 정의하는 것입니다. 다음 사항에 유의하십시오. * 에 추가됨. function 키워드입니다. 함수는 다음과 같이 불립니다. Add 매개변수를 받습니다. x.
  2. The yield 이 키워드는 제너레이터에 특화되어 있으며 함수 실행 도중에 일시 중지됩니다. 실행은 여기서 멈춥니다. next() 호출됩니다.
  3. 두 번째 yield 이 함수는 일시 중지되는 동시에 다음 함수에 전달되는 값을 받습니다. next() 호출은 값이 됩니다 y.
  4. 호출 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) 필요한 시간 지연 코드를 포함하여 콜백 함수를 정의하십시오.

콜백과 콜백 Generators

function Timedelay(ptime, callback) {

    setTimeout(function() {

        callback("Pausing for " + ptime);

    }, ptime);   // the delay must use ptime, the parameter name
}

Code 설명

  1. 함수라고 불리는 Timedelay 매개변수를 사용하여 생성됩니다. ptime여기에는 일시 정지할 밀리초 수를 나타내는 값이 포함됩니다.
  2. setTimeout 해당 밀리초 동안 기다린 후 제공된 콜백 함수를 호출합니다.

⚠️ 정정: 원래 코드가 통과했습니다 time 두 번째 논거로서 setTimeout하지만 이름이 지정된 변수는 없습니다. time 존재합니다 — 매개변수는 ptime글에 쓰여진 대로라면 그것은 던져진다 ReferenceError: time is not defined.

단계 2) 이제 콜백을 사용하는 코드를 살펴보겠습니다. 1000, 2000, 3000밀리초의 지연을 순차적으로 발생시키려면 콜백 함수들을 서로 중첩시켜야 합니다.

콜백과 콜백 Generators

Timedelay(1000, function(message) {

    console.log(message);

    Timedelay(2000, function(message) {

        console.log(message);

        Timedelay(3000, function(message) {

            console.log(message);
        });
    });
});

Code 설명

  1. Timedelay 이 함수는 1000이라는 값을 가지고 콜백으로 호출됩니다.
  2. 해당 콜백 내부에서, Timedelay 2000으로 다시 호출됩니다.
  3. 그 안에는, Timedelay 3000으로 세 번째 호출됩니다.

⚠️ 정정: 원래 로그에 기록된 각 콜백 msg하지만 매개변수의 이름은 다음과 같습니다. message세 줄 모두 던졌습니다. ReferenceError: msg is not defined.

위 코드에서 볼 수 있듯이 호출이 추가될 때마다 코드가 점점 더 복잡해지는데, 이러한 중첩 구조가 바로 콜백 지옥(callback hell)을 의미합니다.

단계 3) 이제 제너레이터를 사용하여 동일한 동작을 살펴보세요. 이 시퀀스는 세 단계의 중첩 구조가 아니라 세 개의 평평한 선으로 표시됩니다.

콜백과 콜백 Generators

function* Messages() {
    console.log(yield Timedelay(1000));
    console.log(yield Timedelay(2000));
    console.log(yield Timedelay(3000));
}

Code 설명

  1. 제너레이터 함수가 정의되어 호출됩니다. Timedelay 기능.
  2. yield 와 함께 사용됩니다 Timedelay 매개변수 값은 1000입니다.
  3. yield 2000과 함께 다시 사용되고, 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 구문이 실제로 해당 오류를 인식하고 처리할 수 있습니다.

자주 묻는 질문

두 개의 속성을 가진 객체: value양보받은 것을 모두 붙잡고, done생성기가 완료되면 true가 되는 부울 값입니다. 실행기는 종료 시점을 알기 위해 테스트를 수행합니다.

네. 무한 루프를 포함하는 제너레이터는 `next()`가 호출될 때까지 아무 계산도 수행되지 않으므로 안전합니다. 이러한 특성 덕분에 제너레이터는 식별자 스트림이나 페이지네이션된 결과를 처리하는 데 매우 적합합니다.

예. AI 도구는 yield를 await로 바꾸고 실행자를 완전히 제거합니다. Rev지연 시퀀스를 주의 깊게 살펴보세요. 왜냐하면 절대 완료되지 않는 생성기는 async await에 직접적으로 대응하는 것이 없기 때문입니다.

AI 어시스턴트 trac실행기가 다음 호출을 중단했는지, 재개 콜백이 호출되지 않았는지, 또는 완료 상태에 도달하지 않았는지 여부가 중요합니다. 이 세 가지가 거의 모든 제너레이터 정지 현상의 원인입니다.

아니요. 비동기 생성기가 선언되었습니다. async function* 그리고 ~와 함께 소비됩니다 for await...of이는 두 가지 아이디어를 모두 결합한 것으로, 데이터베이스 커서와 같은 비동기 데이터 스트리밍에 적합합니다.

이 게시물을 요약하면 다음과 같습니다.