Правильный способ использования потока NodeJS в буфер и поток записи

Мне нужно направить читаемый поток как в буфер (для преобразования в строку), так и в файл. Поток исходит от node-fetch.

Потоки NodeJS имеют два состояния: приостановлено и выполняется. Насколько я понимаю, как только будет подключен слушатель 'data', поток перейдет в непрерывный режим. Я хочу убедиться, что то, как я читаю поток, не потеряет ни одного байта.

Способ 1: передача и чтение из 'data':

fetch(url).then(
  response =>
    new Promise(resolve => {
      const buffers = []
      const dest = fs.createWriteStream(filename)
      response.body.pipe(dest)
      response.body.on('data', chunk => buffers.push(chunk))
      dest.on('close', () => resolve(Buffer.concat(buffers).toString())
    })
)

Способ 2: использование сквозных потоков:

const { PassThrough } = require('stream')
fetch(url).then(
  response =>
    new Promise(resolve => {
      const buffers = []
      const dest = fs.createWriteStream(filename)
      const forFile = new PassThrough()
      const forBuffer = new PassThrough()
      response.body.pipe(forFile).pipe(dest)
      response.body.pipe(forBuffer)
      forBuffer.on('data', chunk => buffers.push(chunk))
      dest.on('close', () => resolve(Buffer.concat(buffers).toString())
    })
)

Требуется ли второй метод, чтобы не было потерянных данных? Является ли второй метод расточительным, поскольку можно буферизовать еще два потока? Или есть другой способ одновременно заполнить буфер и записать поток?


person andykais    schedule 16.07.2018    source источник
comment
На самом деле он работает, как и ожидалось, я просто не был уверен, что мне повезло с быстрым потоком записи. Я прочитал несколько сообщений, в которых говорилось, что потоки записи будут пытаться вызывать метод read в своем собственном темпе (вытягивание), и я также читал, что слушатель «данных» заставит пар течь постоянно (нажимая)   -  person andykais    schedule 17.07.2018
comment
Вы можете просто использовать fs.writeFile(), если вы собираетесь сначала прочитать весь файл в память. Нет необходимости .pipe() это. Если вам не нужен весь файл в памяти, то .pipe() более эффективен.   -  person jfriend00    schedule 17.07.2018


Ответы (1)


Вы не пропустите никаких данных, так как .pipe внутренне вызывает src.on('data') и записывает любой фрагмент в целевой поток.

Таким образом, любой фрагмент, записанный в ваш поток dest, также будет отправлен в response.body.on('data'), где вы буферизуете фрагменты. В любом случае вы должны прослушивать события 'error' и отклонять их, если возникает какая-либо ошибка.

И пока ваш второй режим будет работать, он вам не нужен.


Это фрагмент кода из .pipe. функция

  src.on('data', ondata);
  function ondata(chunk) {
    debug('ondata');
    var ret = dest.write(chunk);
    debug('dest.write', ret);
    if (ret === false) {
      // If the user unpiped during `dest.write()`, it is possible
      // to get stuck in a permanently paused state if that write
      // also returned false.
      // => Check whether `dest` is still a piping destination.
      if (((state.pipesCount === 1 && state.pipes === dest) ||
           (state.pipesCount > 1 && state.pipes.indexOf(dest) !== -1)) &&
          !cleanedUp) {
        debug('false write response, pause', state.awaitDrain);
        state.awaitDrain++;
      }
      src.pause();
    }
  }
person Marcos Casagrande    schedule 17.07.2018