기술나눔

ES6 제너레이터 함수의 비동기적 적용 (8)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

ES6 Generator 함수의 비동기 적용은 주로 Promise와 함께 사용하여 구현됩니다. 이 패턴을 "썽크" 패턴이라고 하며 이를 사용하면 동기적인 것처럼 보이는 비동기 코드를 작성할 수 있습니다.

특성:

  1. 실행 일시 중지: Generator 함수가 항복 표현식을 만나면 실행을 일시 중지하고 Promise가 해결될 때까지 기다립니다.
  2. 실행 재개: Promise가 완료되면(해결 또는 거부) Generator 함수가 실행을 재개하고 항복 표현식의 결과를 반환합니다.
  3. 오류 처리: 비동기 작업의 오류를 캡처하고 처리할 수 있습니다.
  4. 체인콜: 각 작업은 이전 작업이 완료된 후 시작되는 비동기 작업 체인을 만들 수 있습니다.

1. 기본 비동기 생성기 기능

function delay(time) {
    return new Promise(resolve => setTimeout(resolve, time));
}

function* asyncGenerator() {
    console.log("Start");
    yield delay(1000); // 等待1秒
    console.log("After 1 second");
    yield delay(1000); // 再等待1秒
    console.log("After another second");
    return "Done";
}

let gen = asyncGenerator();

function runGenerator(g) {
    let result = g.next();
    result.value.then(() => {
        if (!result.done) {
            runGenerator(g);
        }
    });
}

runGenerator(gen);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2. for…of 및 async…await 구문 설탕을 사용하세요.

// 假设我们有以下 async generator
async function* asyncGen() {
    yield await Promise.resolve(1);
    yield await Promise.resolve(2);
    yield await Promise.resolve(3);
}

// 我们可以使用 for...of 循环和 async...await 语法糖来简化调用
(async () => {
    for await (let value of asyncGen()) {
        console.log(value); // 依次输出 1, 2, 3
    }
})();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3. 비동기 작업의 오류 처리

function* asyncGenWithError() {
    try {
        yield Promise.reject("Error occurred!");
    } catch (e) {
        console.log(e); // 输出:Error occurred!
    }
}

let genWithError = asyncGenWithError();

genWithError.next().value.catch(err => console.log(err));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4. 다른 비동기 제너레이터 함수에 위임하려면 Yield*를 사용하세요.

function* innerAsyncGen() {
    yield Promise.resolve("A");
    yield Promise.resolve("B");
}

function* outerAsyncGen() {
    yield "Start";
    yield* innerAsyncGen(); // 委托给另一个异步 Generator 函数
    yield "End";
}

let outerGen = outerAsyncGen();

function runOuterGenerator(g) {
    let result = g.next();
    result.value.then(val => {
        if (!result.done) {
            runOuterGenerator(g);
        }
    });
}

runOuterGenerator(outerGen);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23