I love functional languages like Elixir + Elm that give you a pipe syntax for control flow:
data
|> first_transformation
|> second_transformation
|> etc
It's easy to understand what this program is doing! I've been learning about how promises work in JavaScript, and they seem like a good way to mimic this kind of data-chaining, even if your functions aren't really doing anything that needs to be asynchronous:
first_transformation(data)
.then(second_transformation)
.then(third_transformation)
.catch(handle_errors_from_the_whole_chain)
The MDN docs on Control flow and error handling suggest that promises are mostly for async/deferred operations. Is it normal to use promises merely as a mechanism for control flow and organization? Is it a horrible idea for some reason?
Top comments (7)
As they mention, it is for async / deferred operations so not a good use case for synchronous operations. Good news though, the pipeline operator was proposed and is moving along quite well. If you want to read about it, @kayis has an article that talks about it.
In the meantime while we wait for the pipeline operator, you could compose your functions. If you're new to composition, @kyleshevlin offers a short but very clear and informative explanation in his egghead.io video, Build Complex Functions with Function Composition in JavaScript.
That's good news that JS is getting a pipeline operator! I'm occasional enough with my JS coding that I prefer to skip using build environments like Babel if I can, but it'll be awesome when that feature gets wider browser support.
I haven't watched the video, but in DuckDuckGo'ing JS composition of course it makes sense - you just manually curry your functions. I've been spoiled by languages that do that for me :)
I still like the part where promises let me pass errors through + deal with them at the end... I wonder about a good composable way to do that...
I haven't done much RxJS, but that's probably a good use case for piping. See RxJS 5.5, piping all the things.
This is reasonable. The separate functions get queued as microtasks in the event loop and will probably complete in the same loop depending on how fast they return. The overhead of a Promise is minimal and modern javascript engines (if you're running this in a browser) are already well optimized for it.
The downside is you may need to continue using Promises if you want to deal with the result of the entire chain inline with other stuff, or you can just use an
await
at the beginning.This is a good point - once you start promising you can't stop! Thanks for pointing that out - it's definitely helpful to keep in mind.
I haven't done speed tests, but I've run tests to see if I can get promises in a chain to run out of order, and I haven't found a way to break it yet. Admittedly, I'm no JavaScript hacker, but I'm generally pleased with the approach thus far.
I love to use these functions for the function composition.
The name"dot" comes from Haskell just like "pipe" from elm. It's the reverse of the pipe function.
Ooh those are handy. Thanks for sharing!