The specification I'm referring to is at http://promises-aplus.github.io/promises-spec/.
When using then()
, you can either return a promise, and reject the promise when you desire, or you can throw an exception to reject a promise.
Why wasn't the api designed in such a fashion where for the then
function, it is passed a resolve and reject function like the original promise constructor?
Exceptions are heavy in many languages (and I assume in javascript too) so it seems odd they are using them as a choice for flow control. Creating a whole new promise object and returning it, just to reject it, adds to code bloat IMO. Debugging becomes harder too in case of an exception is thrown (such as syntax errors, or if function is being called on a undefined object, etc.)
Why wasn't the api designed in such a fashion where for the then function, it is passed a resolve and reject function like the original promise constructor?
Actually, the API in that spec emerged as a consensus amongst various implementations. However, some points that might have led to this are:
then
is a rather functional method. It's callback only should receive one data argument, the result value of the promise.resolve
/reject
functions to the callback does not work well with multiple arguments or even variadic functions.then
is usually used as a plain mapping function. You simply return
the new value, no resolve
is needed.resolve
/reject
, you better should use a promise anyway - which you simply can return then.I once implemented a Promise lib with optional resolve
/reject
arguments, but it was tedious to use - and I seldom needed them because of #4. Using them was error-prone, you could easily forget something (like handling errors, or progress events) - just like the people who are manually constructing and returning deferreds that are resolved from promise callbacks, instead of calling then
.
Exceptions are heavy so it seems odd they are using them as a choice for flow control.
They're not really meant to be used for control flow (like branching, loops etc) but for exception handling: rejections are exceptional. Most Promise developers wanted to implement them as an alternative for synchronous (blocking) code - where IO was always throwing exceptions, so they adapted this. Rejections are still explained as the asynchronous equivalent to try … catch
, though their monadic nature could be utilized in mightier ways and higher-level applications.
Creating a whole new promise object and returning it, just to reject it, adds to code bloat IMO.
There's not much difference between return new RejectedPromise(…)
, return reject(…)
and throw Error(…)
.
Debugging becomes harder too in case of an exception is thrown (such as syntax errors, or if function is being called on a undefined object, etc.)
Most Promise developers seem to see this as an advantage actually - (unexpected) exceptions even in asynchronous code will be caught automatically, so they can be handled instead of blowing up the program (unnoticed). See also exception handling, thrown errors, within promises and acceptable promise pattern for 'LOUD' errors?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With