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 <oliver.le...@gmail.com> 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 <jo...@jorgechamorro.com> 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 nodejs@googlegroups.com >> To unsubscribe from this group, send email to >> nodejs+unsubscr...@googlegroups.com >> 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 nodejs@googlegroups.com > To unsubscribe from this group, send email to > nodejs+unsubscr...@googlegroups.com > 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 nodejs@googlegroups.com To unsubscribe from this group, send email to nodejs+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/nodejs?hl=en?hl=en