Как получить значение генератора

#javascript #typescript #generator

#javascript #typescript #генератор

Вопрос:

scenario.ts

 export interface Step {
    text: string;
    image: string;
    time: number
}

export interface IScenario {
    name: string;

    steps: Array<Step>;
}
  

Restaurant.ts

 import {IScenario, Step} from './interfaces/scenario'

export default class Restaurant implements IScenario {
    name: string = 'Приключение в ресторане';

    steps: Array<Step> = [
        {
            text: 'Вы пришли в ресторан',
            image: 'https://sun9-3.userapi.com/55H3n5pt-TvwwdQzmpBZ9mcHURCqf85x1mXvlw/oyI4OlFu3R0.jpg',
            time: 2000,
        },
        {
            text: 'Перед вами стоит стол',
            image: '',
            time: 5000,
        },
    ];

    private *enumerateSteps(steps: Array<Step>): IterableIterator<Step> {
        yield step;
    }   

    start(): void {
        for (const step of this.enumerateSteps(this.steps)) {
            setTimeout(() => {
                return console.log(step.text);
                step.next();
              }, step.time);
        }
    }
}
  

Я хочу получить следующий шаг через некоторое время, но получаю сообщение об ошибке:

Свойство ‘next’ не существует для типа ‘Step’.

И у меня также есть ошибка об отсутствии step по какой-то причине, но я не знаю почему.

Комментарии:

1. » ошибка об отсутствии step по какой-то причине » — да, в step вашем методе не определена переменная enumerateSteps . Что вы ожидали, что это будет? Обратите внимание, что вы также нигде не используете аргумент steps . (Но это не похоже на опечатку, поскольку они имеют разные типы).

2. Я хочу получить настоящее step в каждом случае. Я попытался обновить генератор const current = steps[0]; yield current; , но все равно получаю сообщение об ошибке «Свойство ‘next’ не существует для типа ‘Step’:

3. Похоже, вы пытаетесь асинхронно выполнить итерацию по своему генератору. В этом случае, как отметил @Bergi, в нем нет необходимости, но язык допускает асинхронные взаимодействия .

4. Ответ Берги отличный, но еще одна проблема с вашим кодом — если вы yield используете функцию генератора только один раз (не в цикле), вы выполняете итерацию только один раз. Другими словами, [...({ *[Symbol.iterator]() { yield 1 } })] просто [1] .

5. Спасибо всем 🙂

Ответ №1:

Вы вообще не должны использовать генераторы здесь. То, что вы хотите, может быть выполнено с помощью подхода, основанного на обратном вызове

 start(callback?: () => void): void {
    this.steps.reduceRight((next, step) => () => {
        console.log(step.text);
        setTimeout(next, step.time);
    }, () => {
        console.log('All steps done');
        callback?.();
    })();
}
  

или с помощью обещаний и async / await :

 async start(): Promise<void> {
    for (const step of this.steps) {
        console.log(step.text);
        await new Promise(resolve => setTimeout(resolve, step.time));
    }
    console.log('All steps done');
}