There is one very good reason for using streams in a case like this,
that no one has mentioned yet.
First, lets just suppose that N is very large.
Also lets generate primes in nextTick so that it never blocks for very long.
And the thing that consume's the primes (data) only needs one at a time.
There could be a variety of reasons for this. one might be that it's
serializing them as a web service.
Now, streams have a cool feature that EventEmitters do not have.
pause()/resume()
Like streams, TCP also has pause. If the pipe is congested or packets
are being dropped
TCP actually slows down a bit.
So if you've made PrimeStream respect pause/resume then it will only
go as fast as the bottleneck (tcp) can handle them!
you can't do that will callbacks.
a callback might be fine if I only want N < ~500 but what if I want
billions and billions of primes?
what if I didn't know how many primes I want. I could just say give me
ALL the primes!
(N = Infinity) and then close the connection when I'm satisfied.
Another benefit of using streams is that you don't need to keep
everything in memory.
you can upload a file that is larger than your ram with streams (I
think you might need to keep a list of primes to calc the next prime,
so this benefit doesn't apply to this case)
in summary, use streams if:
* you can start using the data before you have received everything.
* you would like to be able to throttle the rate something is produced.
usually this is IO related. although, if you have I --> O it may make
sense to keep the _through_ part in the shape of a stream also.
use callbacks if:
* you can't do the next thing until after a thing is done.
* you need the whole thing.
example: create a driectory, delete a file. parse a JSON document
(note, if the document is LARGE and list like, it may make sense to
stream it)
use an EventEmitter if:
* many things will happen
* things will happen more than once.
* multiple listeners may be interested in an event.
note: createServer(function (req, res) {...
is not a callback, because callbacks ALWAYS have err as the first argument.
as pointed out above. it's an event listener. which has no error argument.
On Sat, Apr 28, 2012 at 10:23 PM, Oliver Leics <[email protected]> wrote:
> As i see it: We have a prime number generator that constantly *emits*
> prime numbers. This is a *stream* of prime numbers. Thus: Use
> stream.Stream.
>
> IMHO implementing this as a stream it is not over-engineered. For me
> it is the optimum way as streams provides a standard method for
> everything emitting data. It makes it very easy to hook into that
> stream of data and do whatever needs to be done with that prime
> numbers. I do not have to read lots of API documentation. All i need
> to know: It is a standard node stream of data.
>
> BTW: I'm writing this as i recently added 'lazy' to my toolbelt of
> indispensable node modules.
>
> On Sat, Apr 28, 2012 at 12:04 PM, Jorge <[email protected]> wrote:
>> Hi Bruno,
>>
>> On Apr 28, 2012, at 11:14 AM, Bruno Jouhier wrote:
>>
>>> Neither!
>>>
>>> I think that question should be callbacks vs. events vs. streams:
>>> • Callback: called only once, when the function is done, to return
>>> result (optional) or error.
>>> • Event: called repeatedly by the function to notify its listeners.
>>> Can be used to send intermediate results as they come.
>>> • Stream: higher level concept based on events, with standardized
>>> event types (data, end, error, drain) and standardized API (pause, resume,
>>> write, ..).
>>> So, assuming prime computation is asynchronous:
>>>
>>> • If the function computes the N first primes and returns them all at
>>> once, it should use a callback.
>>> • If the function returns the primes one by one, it should use
>>> events. It may also use a stream but that seems a bit over-engineered.
>>
>>
>> Good, yes, that's the way it is in node, but it does not explain *why* it is
>> so.
>>
>> .readFile() could as well deliver the chunks to the cb as they're read from
>> disk, and to use it you'd need to write just one line:
>>
>> fs.readFile(path, cb);
>>
>> While to do the same with an evented interface there's a lot of boilerplate
>> to write, and an extra object to create:
>>
>> reader= new fileReaderConstructor(path);
>> reader.on('data', cb);
>> reader.on('end', endCB);
>> reader.on('error', errorCB);
>>
>> It seems to me that the former is more functional and makes good use of
>> closures (*), while the latter is the approach a classic OOP programmer
>> would tend to write instead.
>>
>> (*)In JavaScript we don't need to create objects to save state.
>> --
>> Jorge.
>>
>> --
>> Job Board: http://jobs.nodejs.org/
>> Posting guidelines:
>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> You received this message because you are subscribed to the Google
>> Groups "nodejs" group.
>> To post to this group, send email to [email protected]
>> To unsubscribe from this group, send email to
>> [email protected]
>> For more options, visit this group at
>> http://groups.google.com/group/nodejs?hl=en?hl=en
>
>
>
> --
> Oliver Leics @ G+
> https://plus.google.com/112912441146721682527
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to [email protected]
> To unsubscribe from this group, send email to
> [email protected]
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en
--
Job Board: http://jobs.nodejs.org/
Posting guidelines:
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en