Size: a a a

NodeUA - JavaScript and Node.js in Ukraine

2020 December 18

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
Привет всем, не подскажете по стримам момент? Нужно обернуть
 fs.createReadStream 
в промис.

Проблема что для этого нужно дождаться ивента "end", а ивент не триггерится, если присутствует обработчик на "end", но нет обработчика на "data", а в случае выполнения кода ниже - событие "end" выполняется, но стрим возвращается пустой. С данными стрима делать ничего не надо, считываю файл для дальнейшей отправки на фронт.

export const asyncReadStream = (fileName) => {
 return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(fileName)
       readStream.on('end', () => {
         resolve(readStream);
       })
       readStream.on('data', (data) => {
         console.log('stream data', data)
       })
   })
}
источник

TS

Timur Shemsedinov in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
Привет всем, не подскажете по стримам момент? Нужно обернуть
 fs.createReadStream 
в промис.

Проблема что для этого нужно дождаться ивента "end", а ивент не триггерится, если присутствует обработчик на "end", но нет обработчика на "data", а в случае выполнения кода ниже - событие "end" выполняется, но стрим возвращается пустой. С данными стрима делать ничего не надо, считываю файл для дальнейшей отправки на фронт.

export const asyncReadStream = (fileName) => {
 return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(fileName)
       readStream.on('end', () => {
         resolve(readStream);
       })
       readStream.on('data', (data) => {
         console.log('stream data', data)
       })
   })
}
Этого делать не нужно, стримы и промисы - это принципиально разные подходы к асинхронному программированию.
источник

Ш

Шима in NodeUA - JavaScript and Node.js in Ukraine
Георгий - напиши какие тебе данные надо обработать?
источник

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
Шима
Георгий - напиши какие тебе данные надо обработать?
нужно вывести сsv файл на фронт
данные файла уже готовы, ничего делать с ними не нужно

на фронте я преобразовываю респонс в blob и скачиваю файл

upd: ок, если стримы и промисы - разные подходы и использовать их вместе - антипаттерн, то как правильно задержать выполнение основного потока хендлера, пока не fs.createReadStream не стриггерит "end" ивент?
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
Привет всем, не подскажете по стримам момент? Нужно обернуть
 fs.createReadStream 
в промис.

Проблема что для этого нужно дождаться ивента "end", а ивент не триггерится, если присутствует обработчик на "end", но нет обработчика на "data", а в случае выполнения кода ниже - событие "end" выполняется, но стрим возвращается пустой. С данными стрима делать ничего не надо, считываю файл для дальнейшей отправки на фронт.

export const asyncReadStream = (fileName) => {
 return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(fileName)
       readStream.on('end', () => {
         resolve(readStream);
       })
       readStream.on('data', (data) => {
         console.log('stream data', data)
       })
   })
}
Если нужно прочитать файл и сразу отправить клиенту, то можно сделать pipe в response
источник

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
Yevhen
Если нужно прочитать файл и сразу отправить клиенту, то можно сделать pipe в response
тип fs.createReadStream(fileName).pipe(res) ?
у меня koa.js, не уверен что так можно там, но я проверю
Спасибо!
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
тип fs.createReadStream(fileName).pipe(res) ?
у меня koa.js, не уверен что так можно там, но я проверю
Спасибо!
Ага, именно
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
тип fs.createReadStream(fileName).pipe(res) ?
у меня koa.js, не уверен что так можно там, но я проверю
Спасибо!
Я не проверял в Koa, но должно работать. Response должен быть стримом
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
тип fs.createReadStream(fileName).pipe(res) ?
у меня koa.js, не уверен что так можно там, но я проверю
Спасибо!
Еще проверьте с большими файлами и медленным подключением. У меня в express бывали ситуации когда response закрывался до того как клиент успевал получать все данные из стрима. В итоге приходил поврежденный файл
источник

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
Yevhen
Еще проверьте с большими файлами и медленным подключением. У меня в express бывали ситуации когда response закрывался до того как клиент успевал получать все данные из стрима. В итоге приходил поврежденный файл
вот я возвращал до этой ситуации с промисом ctx.body =  fs.createReadStream(fileName) и у меня такой же бихейвьор был.
иногда ок файл возращался, иногда только заголовок csv таблицы, иногда пустой, поэтому и хотел задержать поток до получения всех данных

попробую момент с пайпом
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
И имейте в виду, что с пайпом res закроется когда прочитает все данные из readable stream. Это на случай если у вас есть middlewares которые отрабатывают после отправки файла
источник

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
Yevhen
И имейте в виду, что с пайпом res закроется когда прочитает все данные из readable stream. Это на случай если у вас есть middlewares которые отрабатывают после отправки файла
ок, понял
источник

Г

Глеб in NodeUA - JavaScript and Node.js in Ukraine
Еще, кстати, если в будущем планируются какие-то доп. действия в конвейере (например, сжать файл и записать на диск), можно посмотреть на метод pipeline из нативного модуля stream.

Если нужен async/await синтаксис, например, чтоб ошибки ловить не в хендлере события ‘error’, а в обычном catch’е, но при этом есть необходимость в конвейере потоков, можно сделать что-то вроде:

const asyncPipeline = util.promisify(pipeline)


await asyncPipeline(sourceStream, s2, s3, …, destinationStream)


этот метод грамотно разберется с эррор хендлингом + избавит от необходимости устанавливать сторонние либы типа pumpify
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
вот я возвращал до этой ситуации с промисом ctx.body =  fs.createReadStream(fileName) и у меня такой же бихейвьор был.
иногда ок файл возращался, иногда только заголовок csv таблицы, иногда пустой, поэтому и хотел задержать поток до получения всех данных

попробую момент с пайпом
Можно попробовать повесить promise на событие "end" в res
Мне так и пришлось сделать в express в варианте с пайпом
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
Но сейчас прочитал, что написал @gtumakov и понял, что так было бы лучше)
Спасибо!
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
источник

М

МС Бэнтли in NodeUA - JavaScript and Node.js in Ukraine
ооо, прикольная штука, попробую
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
МС Бэнтли
ооо, прикольная штука, попробую
Получится то же самое, что я описал, только красивее и более читаемо.
И опять же, имейте в виду, что после этого писать в res уже не получится
источник

Y

Yevhen in NodeUA - JavaScript and Node.js in Ukraine
Глеб
Еще, кстати, если в будущем планируются какие-то доп. действия в конвейере (например, сжать файл и записать на диск), можно посмотреть на метод pipeline из нативного модуля stream.

Если нужен async/await синтаксис, например, чтоб ошибки ловить не в хендлере события ‘error’, а в обычном catch’е, но при этом есть необходимость в конвейере потоков, можно сделать что-то вроде:

const asyncPipeline = util.promisify(pipeline)


await asyncPipeline(sourceStream, s2, s3, …, destinationStream)


этот метод грамотно разберется с эррор хендлингом + избавит от необходимости устанавливать сторонние либы типа pumpify
Пойду у себя переписывать на pipeline с promisify, как раз нужно архивировать перед отправкой)
источник

AL

Andrey Listochkin in NodeUA - JavaScript and Node.js in Ukraine
Если Нод свежий, то можно без промисифая:  const { pipeline } = require('stream/promises');
источник