Pushing and pulling
We have seen how a Readable implementation will use push to populate the stream buffer for reading. When designing these implementations, it is important to consider how volume is managed, at either end of the stream. Pushing more data into a stream than can be read can lead to complications around exceeding available space (memory). At the consumer end, it is important to maintain awareness of termination events, and how to deal with pauses in the data stream.
We might compare the behavior of data streams running through a network with that of water running through a hose.
As with water through a hose, if a greater volume of data is being pushed into the read stream than can be efficiently drained out of the stream at the consumer end through read, a great deal of back pressure builds, causing a data backlog to begin accumulating in the stream object's buffer. Because we are dealing with strict mathematical limitations, read simply cannot be compelled to release this pressure by reading more quickly—there may be a hard limit on available memory space, or other limitations. As such, memory usage can grow dangerously high, buffers can overflow, and so forth.
A stream implementation should therefore be aware of, and respond to, the response from a push operation. If the operation returns false , this indicates that the implementation should cease reading from its source (and cease pushing) until the next _read request is made.
In conjunction with the above, if there is no more data to push but more is expected in the future, the implementation should push an empty string (""), which adds no data to the queue but does ensure a future readable event.
While the most common treatment of a stream buffer is to push to it (queuing data in a line), there are occasions where you might want to place data on the front of the buffer (jumping the line). Node provides an unshift operation for these cases, whose behavior is identical to push, outside of the aforementioned difference in buffer placement.