Infinite asyncIterator не работает должным образом - PullRequest
0 голосов
/ 08 января 2020

Итак, я пытаюсь создать бесконечный асинхронизатор / генератор. Предполагается, что код выдаст «Hello» и «Hi» для «await of» l oop, а затем всегда ждет следующего значения. Проблема в том, что он не ожидает третьего значения и не печатает 2 после l oop и завершается без ошибок.

Запуск с узлом ts на узле v12.14.0.

 class Source<T> {

    _data: T[] = [];
    _queue: ((val: T) => void)[] = [];

    send(val: T) {
        if (this._queue.length > 0) {
            this._queue.shift()!(val);
        } else {
            this._data.push(val);
        }
    }

    next(): Promise<{ done: boolean, value: T }> {
        return new Promise((resolve, _reject) => {
            if (this._data.length > 0) {
                resolve({ done: false, value: this._data.shift()! });
            } else {
                this._queue.push(value => resolve({ done: false, value }));
            }
        });
    }

    [Symbol.asyncIterator]() {
        return this;
    }

}

(async () => {
    const s = new Source<String>();
    s.send("Hello");
    s.send("Hi");

    console.log(1);

    for await (let str of s) {
        console.log(str);
    }

    console.log(2);
})();

1 Ответ

1 голос
/ 09 января 2020

Неразрешенные обещания не будут блокировать выход из процесса. Взгляните на this .

Пока есть решенное обещание и цепочка, следующая за ним, процесс будет продолжаться. Поскольку вы вызываете s.send() пару раз перед for await, первые две итерации в l oop разрешили обещания и, следовательно, больше кода для запуска. После этого он ожидает невыполненного обещания, что делает ваш звонок на (async () => { ... })() неразрешенным обещанием. Когда код больше не выполняется, процесс завершается.

Чтобы обойти это, вы можете сделать что-нибудь неприятное, например setInterval(() => {}, 999999999). Пока запланировано время ожидания, процесс не завершится.

Мне потребовалось некоторое время, чтобы выяснить, в каком случае мы хотели бы иметь такое поведение - не дожидаясь, пока все обещания не будут решены или отклонены, прежде чем выход.

let p1 = Promise.resolve(1),
    p2 = new Promise(() => {}).then(Promise.resolve(2)),
    p3 = Promise.race([p1, p2]).then(console.log);

p2 никогда не разрешится, и вызов p3 Promise.race() не отменяет p2 * then(). Однако мы ожидаем, что эта программа напечатает 1 и затем завершится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...