Concurrent: A Performant Promises/A+ Library with Scala Awesomeness
Initially, I tried to implement the spec by downloading the community test suite https://github.com/promises-aplus/promises-tests and running my code against it. The tests were a bit overwhelming at first, and I had a hard time figuring out how they were related. After reading (and re-reading) http://promisesaplus.com/, I decided to try to use the node EventEmitter class. I figured the event emitter could track all of the events, call them in order, and ensure each callback would only be executed once. This took care of most of the spec, but made it difficult to ensure as the EventEmitter started complaining about memory leaks.
From the start, I wanted to design a library to work specifically with node.js that blocked the event loop as little as possible. While some libraries resolve promises in the same event loop, I decided to spread them out to execute one callback per event loop. I knew this would have some performance cost, but hoped that it would prevent any promise from blocking the event loop.
Traditionally, developers have used process.nextTick for scheduling callbacks. One downside of nextTick is that it lumps all of the callbacks on the next event loop (unless they exceed the maxTick limit, in which case they go to the following event loop). Alternatively, setImmediate queues each function over all event loops so only one callback runs per event loop. Consequently, concurrent isn’t as fast in sequential tests, but has the potential to prevent an I/O bound system from stalling under heavy load (I haven’t benchmarked this yet, but hope to soon). Other benchmark results for concurrent can be found here: https://github.com/pspeter3/promise-perf-tests
Finally, I liked how the async library supports ES5 collection iterators for dealing with larger data sets across the event loop, so I decided implement them with concurrent as well, and built them using the setImmediate discussed above. This led to a performance tradeoff - it’s not as fast as other libraries resolving on the same event loop, but is less likely to block the event loop and thus starve I/O. Benchmarks of map and reduce are in the performance test results: https://github.com/pspeter3/promise-perf-tests.
I created a performant Promises/A+ library using setImmediate and a lightweight Promises implementation that doesn’t block the event loop. Then I added Scala syntactic sugar and ES5 iterators to make the library easier to use. Finally, I made sure it worked with other Promise libraries and the browser so developers could easily use it wherever they want.