states.markdown 3.9 KB

Stream state diagrams.

interpretation of these diagrams: boxes are states. arrows are transitions. transitions are labled with the events which cause those transitions. if an event is mentioned on the diagram, but is not on a transition from a particular state, it means that event is forbidden in that state.

if an event is not mentioned in a diagram, then that event is not forbidden, just irrelevant.

where events are listed next to a transition, it means that any of those events may cause that transition.

combining diagrams: I have represented stream behaviour across multiple diagrams for simplicity. Stream implementations must satisify all relevant diagrams.

write / pause

write()!==false               write()===false
     .--.                         .--.
     |  |                         |  |
     |  v                         |  v
  .---------.  write()===false .--------.
  |         |----------------->|        |
  | !paused |                  | paused |
  |         |<-----------------|        |
  `---------`     'drain'      `--------`
               

A WritableStream must emit 'drain' to leave the paused state. A WritableStream may only return false from write() when paused. It is recommended that when a WritableStream in not paused, it should return true.

writable/!writable

  write(), 'drain'
     .--.
     |  |
     |  v
  .----------.                .-----------.
  |          |--------------->|           |
  | writable |   end(),       | !writable |
  |          |   destroy()    |           |
  `----------`                `-----------`
        |                          |
        |                          |  'error', 'close'
        |                          v
        |                     .-----------.
        |  'error'            |           |
        `-------------------->| closed,   |
                              | !writable |
                              |           |
                              `-----------`

A WritableStream may not emit 'drain' or permit write() after end(), 'error' or destroy() have occured. A WritableStream must eventually emit 'close', unless there is an 'error'.

write() may throw, if called when !writable, end() should just be ignored if called when !writable, in 0.8 and earlier pipe does not check writable state before calling end()

read / pause (strict)

'data', 'end'
     .--.
     |  |
     |  v
  .---------.    pause()  .--------.
  |         |------------>|        |
  | !paused |             | paused |
  |         |<------------|        |
  `---------`   resume()  `--------`
  

A strict ReadableStream must not emit 'data' or 'end' when in the paused state.
In 0.8 node http streams are now strict.

read / pause (loose)

'data', 'end',
pause(), resume()
     .--.
     |  |
     |  v
  .---------.
  |         |
  | paused, |
  | !paused |
  `---------`
  

A unstrict ReadableStream should try not to emit 'data' or 'end' when paused.
most streams are unstrict.

readable / !readable

    'data'
     .--.
     |  |
     |  v
  .----------.                .-----------.
  |          |--------------->|           |
  | readable |   'end',       | !readable |
  |          |   destroy()    |           |
  `----------`                `-----------`
        |                          |
        |                          |  'error', 'close'
        |                          v
        |                     .-----------.
        |  'error'            |           |
        `-------------------->| closed,   |
                              | !readable |
                              |           |
                              `-----------`

A ReadableStream must not emit 'data' after 'end', 'error', or destroy(). A ReadableStream must then eventually emit 'close', unless there was an 'error'.