首页 > 解决方案 > 转换流提前停止处理

问题描述

我正在尝试扩展 node.js 转换流两次,一次将标准输入拆分为新行,另一次用于交替小写和大写。

SplitLines正在按预期工作,但AlternateUppercase不是。

index.js

const { Transform } = require('stream')

class SplitLines extends Transform {
  _transform(chunk, encoding, callback) {
    const parsed = chunk.toString().trim()
    const results = parsed.split('\n')
    results.forEach((line) => {
      this.push(`${line}\n`)
    })
  }
}

class AlternateUppercase extends Transform {
  constructor(options) {
    super(options)
    this.isEven = false
  }

  _transform(chunk, encoding, callback) {
    const line = chunk.toString()
    const altered = this.isEven ? line.toUpperCase() : line
    this.push(`${altered}\n`)
    this.isEven = !this.isEven
  }
}

process.stdin
  .pipe(new SplitLines())
  .pipe(new AlternateUppercase())
  .pipe(process.stdout)

我如何测试

echo -e 'one\ntwo\nthree' | node index.js

我在终端看到的

one

我希望看到的

one
TWO
three

我做错了什么导致

标签: node.js

解决方案


节点文档中,您需要调用该callback函数才能接收下一个块。这在函数中并不那么明显,SplitLines因为您将整个字符串作为单个块传递。但是,当您重复进行推送操作时SplitLines,您正在发送多个块,因此您需要调用该callback函数。

const { Transform } = require('stream')

class SplitLines extends Transform {
  _transform(chunk, encoding, callback) {
    const parsed = chunk.toString().trim()
    const results = parsed.split('\n')
    results.forEach((line) => {
      this.push(`${line}\n`)
    })
  }
}

class AlternateUppercase extends Transform {
  constructor(options) {
    super(options)
    this.isEven = false
  }

  _transform(chunk, encoding, callback) {
    const line = chunk.toString()
    const altered = this.isEven ? line.toUpperCase() : line
    this.push(`${altered}\n`)
    callback() //must call callback to receive next chunk
    this.isEven = !this.isEven
  }
}

process.stdin
  .pipe(new SplitLines())
  .pipe(new AlternateUppercase())
  .pipe(process.stdout)

输出将是:

one

TWO

three


出现多条新线是因为您\n在两个变压器上。要解决此问题,您只需添加\n一次,即仅在 SplitLines 或 AlternateUppercase 处。


推荐阅读