16

I am very confuse using pipe to handle write stream is sync or not, because I find a question about callback to handle completion of pipe

I just wanna ensure the write stream is done before do others like fs.rename, so I promisify it, code like:

(async function () {
  await promiseTempStream({oldPath, makeRegex, replaceFn, replaceObj, tempPath})
  await rename(tempPath, oldPath)
  function promiseTempStream({oldPath, makeRegex, replaceFn, replaceObj, tempPath}) {
  return new Promise((res, rej) => {
    const writable = fs.createWriteStream(tempPath)
    fs.createReadStream(oldPath, 'utf8')       
      .pipe(replaceStream(makeRegex ,replaceFn.bind(this, replaceObj), {maxMatchLen: 5000}))
    .pipe(writable)
    writable
      .on('error', (err) => {rej(err)})
      .on('finish', res)
    })
}
}())

It works, but I’m confused after read pipe doc, because it says 

By default, stream.end() is called on the destination Writable stream when the source Readable stream emits 'end', so that the destination is no longer writable.

So I only need

await fs.createReadStream(oldPath, 'utf8')
.pipe(replaceStream(makeRegex ,replaceFn.bind(this, replaceObj), {maxMatchLen: 5000}))
.pipe(fs.createWriteStream(tempPath))
await rename(tempPath, oldPath)

or just

fs.createReadStream(oldPath, 'utf8')
.pipe(replaceStream(makeRegex ,replaceFn.bind(this, replaceObj), {maxMatchLen: 5000}))
.pipe(fs.createWriteStream(tempPath))
await rename(tempPath, oldPath)

which is right way to do it? thank you very much

Roy
  • 731
  • 3
  • 10
  • 24

1 Answers1

29

You need to wait for the finish event on the tempPath stream. So you could do something like

async function createTheFile() {
return new Promise<void>(resolve => {
    let a = replaceStream(makeRegex, replaceFn.bind(this, replaceObj), { maxMatchLen: 5000 });
    let b = fs.createWriteStream(tempPath);
    fs.createReadStream(oldPath, 'utf8').pipe(a).pipe(b);
    b.on('finish', resolve);
}
}

await createTheFile();
rename(tempPath, oldPath);

Basically here we have created a promise that resolves when we have completed writing into the tempFile. And you need to await that promise before proceeding ahead.

However it would be great if you also add some error handing code with the streams as mentioned in Error handling with node.js streams

akshita007
  • 549
  • 1
  • 9
  • 15
  • b.on('finish', resolve); or b.on('close', resolve); ? – sawa we Mar 13 '19 at 13:45
  • Stream emits 'finish' when it finishes writing, but the stream may not be closed yet. So 'close' is the final stage when the stream is closed. – Zee Jan 17 '22 at 10:17