Для каждой строки в файле я хочу выполнить вычислительно сложную задачу, например сжатие изображений. У меня проблема в том, что данные поступают слишком быстро и переполняют память. В идеале я хотел бы иметь возможность приостановить и продолжить поток по мере обработки данных.
Сначала я попытался использовать модуль readline
с таким потоком файлов:
const fileStream = fs.createReadStream('long-list.txt')
const rl = readline.createInterface({ input: fileStream })
rl.on('line', (line, lineCount) => {
doTheHeavyTask(line)
})
Однако, это быстро переполняет память тысячами вызовов на doTheHeavyTask()
.
Я остановился на том, чтобы поместить каждую строку в очередь и создать событие, которое удаляет следующую строку, когда предыдущая строка обрабатывается:
const lineQ = new Queue() // From the 'queue-fifo' module
rl.on('line', (line, lineCount) => {
lineQ.enqueue(line)
})
const lineEmitter = new EventEmitter() // From the 'events' module
lineEmitter.on('processNextLine', async () => {
await doTheHeavyTask( lineQ.dequeue() )
if (!lineQ.isEmpty()) lineEmitter.emit('processNextLine')
})
setTimeout( () => lineEmitter.emit('processNextLine'), 20) // Give rl a moment to enqueue some lines
Это работает, но кажется несколько странным и не намного лучше, чем просто чтение в файле сразу.
Я смутно осознаю такие понятия, как "противодавление" и«генераторы» в Javascript, но я не уверен, как их применять.