12

I have the following example

const input = _();
const output = _()
  .each(x => console.log('out', x));

input
  .pipe(output);

input.write(1)
output.destroy();
input.write(2); 

As far as I can read in the documentation (http://highlandjs.org/#destroy) destroying the stream should clean up the broken pipe. In stead I get the following error:

out 1
out 2
node_modules/highland/lib/index.js:1114
        throw new Error('Can not call next after nil');
        ^

Error: Can not call next after nil

Does anyone have some insight into why this happends, and what the correct way to destroy the stream is?

Andreas Møller
  • 839
  • 5
  • 9

1 Answers1

4

From reading the documentation, it looks like This is your answer to your error. The way in which the stream lets the rest of the program know that it has ended is by passing "nil" as the next piece of data on the stream. Looking at the sample code at that link, it's up to you to determine that the stream has ended and act accordingly.

That's why you're getting the error - your pipe is trying to continue on to the next data, but is throwing an error as there is no such thing as next after "nil".

As for the correct way to destroy a stream, I think that the way you are using is the correct way (I'm not that familiar with highland.js, so that's just based on reading the documentation and familiarity with javascript in general), it's just that the effects aren't necessarily what you're expecting. I would not expect destroying the output to destroy the pipe, this is because the pipe "belongs" to input, as that it what it was called against. If you want to destroy your pipe, I would imagine that the way to go about it would be to call

input.destroy()

instead (or indeed, as well as output.destroy(), as you don't want to leave loose ends!). The documentation states that you should call destroy() or .end() on any manually constructed stream (like you have above).

Think about it this way. If I have a source which is piping to a destination, and I remove that destination, of course I'm going to get an error, because my input has nowhere to go, and my output stream is going to be telling everything else that it has ended. If you want to destroy the pipe, it makes more sense to destroy the source, and if you stop the output/destination, you need to find somewhere else for your input to go!

Ieuan Stanley
  • 1,248
  • 8
  • 20
  • Hmmm… okay, this explains things. Thanks for that so far :-). The question is: How can I destroy the output and keep the input stream, as I still need it? OTOH the documentation explicitly states that `destroy()` is also going to remove the stream from any sources, so this sounds as if you should be able to unpipe this way as well from a source stream. – Golo Roden Dec 09 '15 at 09:35
  • This would be a good time to ask yourself what you're trying to achieve! Can a pipe be redirected to a new output? Honestly I can't say categorically, but the question is, do you need to? Once you call .destroy() on output it no longer exists, so you need to do something about your pipe on input. You could try defining a new output and re-calling .pipe on input to that new output, see what happens there. Or you could reconsider destroying output in the first place. Can you redefine what it does instead. Or should you even by reusing input? should just end them all and start with a new set? – Ieuan Stanley Dec 09 '15 at 09:48