Skip to content

Latest commit

 

History

History
181 lines (134 loc) · 4.86 KB

objectMode.md

File metadata and controls

181 lines (134 loc) · 4.86 KB

objectMode

在介绍Readable时,从例子中可以发现一个现象: 生产数据时传给pushdata是字符串或null, 而消耗时拿到的却是Buffer类型。

下来探讨一下流中数据类型的问题。

在创建流时,可指定objectMode选项为true。 此时,称为一个objectMode流。 否则,称其为一个非objectMode流。

更多内容见文档

对Readable的影响

Readable({ objectMode: true })

这个选项将影响push(data)data的类型,以及消耗时获得的数据的类型:

  • 在非objectMode时,data只能是String, Buffer, Null, Undefined。 同时,消耗时获得的数据一定是Buffer类型。
  • objectMode时,data可以是任意类型,null仍然有其特殊含义。 同时,消耗时获得的数据与push进来的一样。实际就是同一个引用。

所谓“缓存”,其实也就是一个数组。可以看看readable._readableState.buffer

每次调用push(data)时,如果是objectMode,便直接调用state.buffer.push(data)。 这里,state = readable._readableState

如果是非objectMode,会将String类型转成Buffer,再调用state.buffer.push(chunk)。 这里,chunk即转换后的Buffer对象。 默认会以utf8的编码形式进行转换。 设置方法查 文档即可。 一般不需要设置。

在消耗objectMode流时,不管是flowing模式,还是paused模式, 都等同于调用state.buffer.shift()拿到数据。 保证push产生的数据会被一一消耗。

在消耗非objectMode流时,flowing模式仍然等同于调用state.buffer.shift()。 但paused模式则会拼接字节数,以满足readable.read(n)n的要求。 如果n没指定,则会一次将state.buffer所有字节拼起来消耗掉。

这里看一个比较有意思的例子来说明objectMode与非objectMode的区别。

objectModepush('')

var Stream = require('stream')

var source = ['a', '', 'c']
var readable = Stream.Readable({
  read: function () {
    var data = source.shift()
    data = data == null ? null : data
    this.push(data)
  },
})

readable.on('end', function () {
  console.log('end')
})

readable.on('data', function (data) {
  console.log('data', data)
})

输出:

⌘ node example/empty-string-non-objectMode.js
data <Buffer 61>
data <Buffer 63>
end

objectModepush('')

var Stream = require('stream')

var source = ['a', '', 'c']
var readable = Stream.Readable({
  objectMode: true,
  read: function () {
    var data = source.shift()
    data = data == null ? null : data
    this.push(data)
  },
})

readable.on('end', function () {
  console.log('end')
})

readable.on('data', function (data) {
  console.log('data', data)
})

输出:

⌘ node example/empty-string-objectMode.js
data a
data
data c
end

可见,非objectMode下直接将push('')给忽略了, 而objectMode下在消耗时能拿到这个空字符串。

(注意,非objectModepush('')实际是会修改内部状态的, 会有一定的副作用,一般不要如此。 见这里

要点

  • objectMode时,可push任意类型的数据,消耗时会逐个消耗同样的数据
  • objectMode时,只能push以下数据类型:String, Buffer, Null, Undefined。 在消耗时只能拿到Buffer类型的数据

对Writable的影响

Writable({ objectMode: true })

这个选项将影响write(data)data的类型,以及底层消耗时获得的数据(_write(chunk, _, next)中的chunk)的类型:

  • 在非objectMode时,data只能是String, Buffer, Null, Undefined。 同时,chunk一定是Buffer类型。
  • objectMode时,data可以是任意类型,null仍然有其特殊含义。 同时,chunkdata

objectMode

var Stream = require('stream')

var writable = Stream.Writable({
  write: function (data, _, next) {
    console.log(data)
    process.nextTick(next)
  },
})

writable.write('a')
writable.write('b')
writable.write('c')
writable.end()

输出:

⌘ node example/writable.js
<Buffer 61>
<Buffer 62>
<Buffer 63>

objectMode

 node example/writable-objectMode.js
a
b
c

什么时候用objectMode

正如文档 中所言,Node.js核心模块没有使用objectMode的,只有Node.js的用户才会用到。

具体某个流是否应当设置objectMode,需要看其所处的上下游。

如果上游是objectMode,且输出的是非StringBuffer,那就必须用objectMode。 如果下游不是objectMode,就必须注意,不要输出非StringBuffer的数据。