On Wed, Oct 1, 2014 at 11:44 AM, Domenic Denicola <dome...@domenicdenicola.com> wrote: > From: whatwg [mailto:whatwg-boun...@lists.whatwg.org] On Behalf Of Tab Atkins > Jr. > >> This is actually kinda terrible. Promises make it *really easy* to deal >> with rejections *later*, letting you execute a bunch of code on the success >> path and only at the end saying "Oh, did something along the line fail? Let >> me take care of that.". Promise is basically an async Maybe monad, which is >> great, because Maybe is useful for *exactly the scenario I just outlined*. > > This is exactly the wrong way to think about promises. Promises are the > "async return/throw monad"; if you want a Maybe, then you have to compose > that in yourself. People often try to abuse the fact that they have a second > branch for exceptions in order to use it as a generic container for "go down > two possible flow paths", but that is very incorrect. An earlier comment in > the thread about "we have three possible mechanisms" is also symptomatic of > this incorrect thinking. We have two mechanisms: return and throw. When you > wrap those in async, they become fulfill and reject. > >> I think we should develop Promises in a way that exploits their ergonomics >> properly, and then rethink async/await a bit to make it match those >> ergonomics, rather than fighting them. > > We are not changing the model of promises in this way. If you want a Maybe > monad, that's a separate API that you'd want to spec.
I've never heard this opinion explicitly expressed, and it has never shown up in any API reviews of promise-using specs. It's directly contrary to the way that existing non-promise async APIs are constructed, and I expect quite contrary to most people's expectations. Geo, for example, throws if you pass bad arguments, but then routes its result through either a success or error callback. This is *directly* analogous to the signature of Promise.then(), and I think a lot of people would expect a getCurrentPosition() that returned a promise would have the same behavior. This allows you to just assume that the value passed to the success callback is a position, and write code accordingly. It feels like your position leads directly to the "error handling in two places" problem that you, I, and others railed against in the "promise-returning functions should never throw" debate. You have to handle bad arguments in the reject callback to the promise, and handle failure in the fulfill callback. It'll lead to a ton of boilerplate `if(arg == null) throw;` at the top of fulfill callbacks, so that the fulfill chain is *actually for the successful case*. ~TJ