Это часть более крупного процесса, который я сократил до минимального воспроизводимого примера в узле v14.4.0. В этом коде он ничего не выводит изнутри for
l oop.
Я вижу только этот вывод в консоли:
before for() loop
finished
finally
done
The for await (const line1 of rl1)
l oop никогда не попадает в for
l oop - он просто пропускает его:
const fs = require('fs');
const readline = require('readline');
const { once } = require('events');
async function test(file1, file2) {
try {
const stream1 = fs.createReadStream(file1);
await once(stream1, 'open');
const rl1 = readline.createInterface({input: stream1, crlfDelay: Infinity});
const stream2 = fs.createReadStream(file2);
await once(stream2, 'open');
const rl2 = readline.createInterface({input: stream2, crlfDelay: Infinity});
console.log('before for() loop');
for await (const line1 of rl1) {
console.log(line1);
}
console.log('finished');
} finally {
console.log('finally');
}
}
test("data/numbers.txt", "data/letters.txt").then(() => {
console.log(`done`);
}).catch(err => {
console.log('Got rejected promise:', err);
})
Но, если я удалю любое из операторов await once(stream, 'open')
, тогда for
l oop делает именно то, что от него ожидается (перечисляет все строки файла rl1
). Итак, по-видимому, есть некоторая проблема синхронизации с итератором asyn c из интерфейса readline между этим и потоком. Любые идеи, что может происходить. Есть идеи, что может быть причиной этого или как его обойти?
FYI, await once(stream, 'open')
существует из-за другой ошибки в итераторе asyn c, где он не отклоняется, если возникает проблема файл, в то время как await once(stream, 'open')
заставляет вас правильно получить отказ, если файл не может быть открыт (по существу, предварительное открытие).
Если вам интересно, почему там код stream2, он используется в более крупном проекте, но я сократил этот пример до минимального воспроизводимого примера, и для демонстрации проблемы требуется только эта часть кода.
Изменить: Пробуя немного другую реализацию, я обнаружил, что если я объединю два вызова once(stream, "open")
в Promise.all()
, то это сработает. Итак, это работает:
const fs = require('fs');
const readline = require('readline');
const { once } = require('events');
async function test(file1, file2) {
try {
const stream1 = fs.createReadStream(file1);
const rl1 = readline.createInterface({input: stream1, crlfDelay: Infinity});
const stream2 = fs.createReadStream(file2);
const rl2 = readline.createInterface({input: stream2, crlfDelay: Infinity});
// pre-flight file open to catch any open errors here
// because of existing bug in async iterator with file open errors
await Promise.all([once(stream1, "open"), once(stream2, "open")]);
console.log('before for() loop');
for await (const line1 of rl1) {
console.log(line1);
}
console.log('finished');
} finally {
console.log('finally');
}
}
test("data/numbers.txt", "data/letters.txt").then(() => {
console.log(`done`);
}).catch(err => {
console.log('Got rejected promise:', err);
});
Очевидно, это не должно зависеть от того, как именно вы ждете открытия файла. Где-то есть ошибка времени. Я хотел бы найти эту ошибку либо в строке чтения, либо в потоке чтения и зарегистрировать ее. Есть идеи?