@@ -63,6 +63,10 @@ some ways superior to) Node.js core streams.
63
63
Please read these caveats if you are familiar with node-core streams and
64
64
intend to use Minipass streams in your programs.
65
65
66
+ You can avoid most of these differences entirely (for a very
67
+ small performance penalty) by setting ` {async: true} ` in the
68
+ constructor options.
69
+
66
70
### Timing
67
71
68
72
Minipass streams are designed to support synchronous use-cases. Thus, data
@@ -82,6 +86,82 @@ This non-deferring approach makes Minipass streams much easier to reason
82
86
about, especially in the context of Promises and other flow-control
83
87
mechanisms.
84
88
89
+ Example:
90
+
91
+ ``` js
92
+ const Minipass = require (' minipass' )
93
+ const stream = new Minipass ({ async: true })
94
+ stream .on (' data' , () => console .log (' data event' ))
95
+ console .log (' before write' )
96
+ stream .write (' hello' )
97
+ console .log (' after write' )
98
+ // output:
99
+ // before write
100
+ // data event
101
+ // after write
102
+ ```
103
+
104
+ ### Exception: Async Opt-In
105
+
106
+ If you wish to have a Minipass stream with behavior that more
107
+ closely mimics Node.js core streams, you can set the stream in
108
+ async mode either by setting ` async: true ` in the constructor
109
+ options, or by setting ` stream.async = true ` later on.
110
+
111
+ ``` js
112
+ const Minipass = require (' minipass' )
113
+ const asyncStream = new Minipass ({ async: true })
114
+ asyncStream .on (' data' , () => console .log (' data event' ))
115
+ console .log (' before write' )
116
+ asyncStream .write (' hello' )
117
+ console .log (' after write' )
118
+ // output:
119
+ // before write
120
+ // after write
121
+ // data event <-- this is deferred until the next tick
122
+ ```
123
+
124
+ Switching _ out_ of async mode is unsafe, as it could cause data
125
+ corruption, and so is not enabled. Example:
126
+
127
+ ``` js
128
+ const Minipass = require (' minipass' )
129
+ const stream = new Minipass ({ encoding: ' utf8' })
130
+ stream .on (' data' , chunk => console .log (chunk))
131
+ stream .async = true
132
+ console .log (' before writes' )
133
+ stream .write (' hello' )
134
+ setStreamSyncAgainSomehow (stream) // <-- this doesn't actually exist!
135
+ stream .write (' world' )
136
+ console .log (' after writes' )
137
+ // hypothetical output would be:
138
+ // before writes
139
+ // world
140
+ // after writes
141
+ // hello
142
+ // NOT GOOD!
143
+ ```
144
+
145
+ To avoid this problem, once set into async mode, any attempt to
146
+ make the stream sync again will be ignored.
147
+
148
+ ``` js
149
+ const Minipass = require (' minipass' )
150
+ const stream = new Minipass ({ encoding: ' utf8' })
151
+ stream .on (' data' , chunk => console .log (chunk))
152
+ stream .async = true
153
+ console .log (' before writes' )
154
+ stream .write (' hello' )
155
+ stream .async = false // <-- no-op, stream already async
156
+ stream .write (' world' )
157
+ console .log (' after writes' )
158
+ // actual output:
159
+ // before writes
160
+ // after writes
161
+ // hello
162
+ // world
163
+ ```
164
+
85
165
### No High/Low Water Marks
86
166
87
167
Node.js core streams will optimistically fill up a buffer, returning ` true `
@@ -97,6 +177,9 @@ If the data has nowhere to go, then `write()` returns false, and the data
97
177
sits in a buffer, to be drained out immediately as soon as anyone consumes
98
178
it.
99
179
180
+ Since nothing is ever buffered unnecessarily, there is much less
181
+ copying data, and less bookkeeping about buffer capacity levels.
182
+
100
183
### Hazards of Buffering (or: Why Minipass Is So Fast)
101
184
102
185
Since data written to a Minipass stream is immediately written all the way
@@ -181,6 +264,8 @@ moving on to the next entry in an archive parse stream, etc.) then be sure
181
264
to call ` stream.pause() ` on creation, and then ` stream.resume() ` once you
182
265
are ready to respond to the ` end ` event.
183
266
267
+ However, this is _ usually_ not a problem because:
268
+
184
269
### Emit ` end ` When Asked
185
270
186
271
One hazard of immediately emitting ` 'end' ` is that you may not yet have had
@@ -197,6 +282,18 @@ To prevent calling handlers multiple times who would not expect multiple
197
282
ends to occur, all listeners are removed from the ` 'end' ` event whenever it
198
283
is emitted.
199
284
285
+ ### Emit ` error ` When Asked
286
+
287
+ The most recent error object passed to the ` 'error' ` event is
288
+ stored on the stream. If a new ` 'error' ` event handler is added,
289
+ and an error was previously emitted, then the event handler will
290
+ be called immediately (or on ` process.nextTick ` in the case of
291
+ async streams).
292
+
293
+ This makes it much more difficult to end up trying to interact
294
+ with a broken stream, if the error handler is added after an
295
+ error was previously emitted.
296
+
200
297
### Impact of "immediate flow" on Tee-streams
201
298
202
299
A "tee stream" is a stream piping to multiple destinations:
@@ -221,7 +318,7 @@ src.pipe(dest1) // 'foo' chunk flows to dest1 immediately, and is gone
221
318
src .pipe (dest2) // gets nothing!
222
319
```
223
320
224
- The solution is to create a dedicated tee-stream junction that pipes to
321
+ One solution is to create a dedicated tee-stream junction that pipes to
225
322
both locations, and then pipe to _ that_ instead.
226
323
227
324
``` js
@@ -258,6 +355,13 @@ tee.on('data', handler2)
258
355
src .pipe (tee)
259
356
```
260
357
358
+ All of the hazards in this section are avoided by setting `{
359
+ async: true }` in the Minipass constructor, or by setting
360
+ ` stream.async = true ` afterwards. Note that this does add some
361
+ overhead, so should only be done in cases where you are willing
362
+ to lose a bit of performance in order to avoid having to refactor
363
+ program logic.
364
+
261
365
## USAGE
262
366
263
367
It's a stream! Use it like a stream and it'll most likely do what you
0 commit comments