What's so great about JavaScript Promises?
blog.parse.com
blog.parse.com
1) Give the illusion that control has been returned to the caller. It hasn't, but it kinda looks like it. This is soothing for people who don't really like JavaScript all that much.
2) Provide a structured way of dealing with callback-oriented code. You don't have to think about in a function whether the callback should be that last parameter, the only parameter. You don't have to think about whether it should include an errback or if the error should instead be the first parameter of the callback. You just do it the way the promises library describes, so the interface is predictable.
#1 is of no concern to me. #2 I feel pretty meh about. A consistent interface is nice, but I don't lose sleep over a library using callbacks in a slightly different way than I like, I just write an extra function or two to wrap it into the way I like and move on with my life. I don't have a problem with Promises per se, I just don't want a library I'm using to pick a winner and tact on an extra few k.
Doesn't look like ES6 is going to pick a promises winner, so I probably will largely ignore it until ES7.
Returning control to the caller is half the story. Along with returning control- which indeed is what is happening, no illusion, if the promise is triggering a non-blocking routine- the promise itself is returned: that object is what makes promises great.
We have no other object for an execution or process in JavaScript: a promise, the value it returns, is an object. Objects can be used and talked about inside JS. If there is no object, there's nothing to compute about. A promise is a first class execution that we can compute about.
> Doesn't look like ES6 is going to pick a promises winner
Why would ES6 "pick a promises winner"? Promises don't need to be a language feature.
(ES6 will probably lead to people using coroutines with promises mostly being an implementation detail of that, e.g. http://taskjs.org/)
If they don't, the surrounding ecosystem is less likely to standardize on a single promise implementation. That means you'll have fragmentation where foo uses Futures and bar uses Promises so you have to use a bunch of Future<->Promise shims to get them to play together.
This is actually something I think is really nice about Dart: Futures are baked into the core library so they are The Way(tm) to pass around asynchronous computations.
At any rate, JavaScript is not built around having a monolithic base library, and as others have pointed out, it would not make sense to have language level support for promises per se.
However, I do agree that it would be great to have host APIs, for example, DOM, to make more widespread use of promises. In fact, WinJS for Windows 8 _does_ make use of promises in their async APIs.
There's no need for a single promise implementation as long as they all implement the same API, in this case CommonJS Promises/A. And for the most part they do and are interoperable.
#1 Promises have strong guarantees. A promise will be resolved at most once, and it will be either resolves successfully or unsuccessfully. This makes reasoning about them and composing them together much easier. For example, whenever I need to perform multiple async calls with callbacks I've always got to write a bit of repetitive error-prone boiler plate to wait for and combine their results. With a good promise library this is a one-liner using a well tested library function.
#2 Error propagation. With callbacks most exceptions vanish into the ether, only catchable by window.onerror and friends. Propagating that promise up to the caller who can handle it is an enormous pain in the ass and requires repetitive error handling code everywhere if you want to be resilient. With promises an exception raised in a handler counts as the resulting promise failing, which can propagate up similarly to the way exceptions propagate with try/catch. Again, this makes writing reliable abstractions so much easier.
In my experience, promises can be more difficult to debug (once the promise library takes my callback, I can't follow the flow of execution until it is called, unless I crack open the library itself), and are less intuitive. While those shouldn't disqualify the idea immediately, it does make me hesitate.
And I'm not sold on the benefits to error handling either. In the author's example, yes, all those error handlers could be grouped together - but how often do you have that many async function calls with identical error handlers? In most situations, that is a warning sign that you aren't handling errors properly and with enough "resolution".
All that said, I don't think promises are useless. There may be times when it makes sense to use them. But calling them the "next great paradigm in JavaScript programming" seems like a bit of a stretch to me.
I would advise most strongly against this exercise in extrapolation: it is not a productive tasks to introduce a new technology via use cases without establishing some grounds for what the technology's role is. You've attempted to define, after reading, what that role is, and that to me bespeaks a horrible exercise that will draw bad results, and it speaks to a poor likely fruitless introduction for people who don't already know.
The net is this: a promise is a value you have, can pass around, can chain more promisary stages of computation on to, or combine with other promises that describes something of the future. You have a symbol for the future that you can continue to operate on. That is the value of promises: it's just an object. There are no other JS constructs we have for a first-class future: the promise is the sum of taking as much away from asynchronous as we can, for boiling the asynchronous future down into a mundane, primitive value. It's surpassing notability is that a promise is just an object, unlike everything else we have for reasoning about the future.
In callback style, one has to know ahead of time what one is doing in the future and have a function fully specified to deal with that. I see promises are fairly close to event style programming using only .once handlers, but the libraries for promises also focus on tasks like combining promises (Q.all, Q.allResolved) and there is chainability and error handling inbuilt: these sum to making Promises far easier to use in practice than I have events.
With promises, you can attach an error handler once. If you think of errors as only unexpected conditions, you can have a single error handler for each set of operations and not have to worry about checking at each step.
var slice = Array.prototype.slice;
function errHandler(callback) {
return function(err) {
if(err) {
// Error handling code here.
} else {
callback(slice.call(arguments, 1));
}
};
} function myAsyncThing(cb) {
var handleErrors = errHandler(cb)
doSomethingElse(handleErrors(function(data) {
// repeat. use handleErrors at each callback.
}))
}
Am I missing something? Can you get it cleaner than that? doSomethingElse(errHandler(function(real, results) {
// foo
}));
If you're using Node you should be writing small(ish) modules anyways, so it doesn't lead to much code blote and its advantageous to consolidate your error handling in one or 2 spots.Or use a sane async library. As far as I can tell, something like https://github.com/caolan/async gives you a strict superset of Promise features, unless you're for some reason tied to how code with promises looks.
See http://taskjs.org/ for how it could work in ES6.
If you want to carry the analogy even further generators can also implement coroutine patterns, if you use yield as an expression (for communication) and yield from to do nested generators.
A promise is agnostic to your concern. Thanks for writing.
There may be some utility in being able to pass them around so that the code that calls the API isn't the place where the block occurs, but I'm not convinced it's worth the extra complexity and API fragmentation to care about that.
In my experience of using fibers in ruby (which I _think_ are substantially/exactly the same as coroutines?), it hasn't been like you describe at all -- promises, or something other higher level abstraction, are still pretty neccesary to do useful and comprehensible things with them. So my experience colors my understanding and I think "What's he talking about, that doesn't make any sense."
More likely, you have experience in a language where things are done differently enough that it all comes out different.
What language?
val resultA = something()
val resultB = somethingElse()
return resultA + resultB
With Futures, the processing for resultA and resultB would be done in parallel, because the call to something() does not block. To combine them you don't even need to wait for the processing to finish, because you just create another Future.Also, being able to pass them around is a really important use-case and Futures are also all about error handling. With Scala it's really trivial to wrap the async support in Servlets 3.0 and make your controllers return Future responses. Then in the servlet you just attach onComplete and onFailure events to return the request when it's ready or when it fails. Works like a charm.
The greatest thing about Futures is that the concept is entirely agnostic to the underlying implementation details. You could have a Future result that's being processed asynchronously by an IO loop (e.g. ning's AsyncHttpClient), you could have a Future result that's being processed by a thread and you can combine the results.
If anything, I don't think you worked with Futures much. You should try it out in Scala, where Futures (from Akka or Scala 2.10) are modelled as monadic types, making them highly composable. Doing multi-threading with Futures in Scala is like working with Lego blocks.
https://developer.mozilla.org/en-US/docs/JavaScript/New_in_J...
try {
await Parse.User.logIn("user", "pass");
var results = await query.find();
await results[0].save(new { key = value });
} catch (Exception e) {
// Some error handling
}
// the object was saved
Does anything exist to do this in JavaScript? Can CoffeeScript emulate it? C# does it entirely in the compiler, I believe.| "An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off."
The implementation detail is that your caller's state needs to somehow be re-asserted when the asynchronous wait finishes evaluating- anyone mildly versed in computer hardware knows that to, in most situations (some green threading environments aside) be a very onerous scary intensive thing, speak nothing of the tasks of capturing and storing the continuation, which likely is fairly deep in a call stack somewhere.
It's great magic, it's certainly putting a lot of magic programmers like to use at their fingertips. But be advised that it is somewhat scary, handing out magic wands like candy to newcomers and telling them it's OK and good.
I still strongly believe it's better to make cool things available rather than try and protect people from themselves.
The actual transformations should be quite straight forward and give you the "pyramid" code the article mentions.
The magic that will bite you isn't the transformation as much as the runtime library that handles threading and the hidden choices made for you there. For instance, in ASP.NET, doing fooAsync().Result causes a deadock.
Besides avoiding highly nested code, and handling certain types of errors better, I've found that they also provide an optional progress callback, in addition to the success and error callbacks in then(). This is highly useful in reporting the progress of a long running process, to help give the user some update or stream the results as it's being completed. That cuts down on both the actual and perceived response time.
In normal callback-style, it's awkward to have two callbacks, one for success/err, and one for progress. In addition, it's not the canonical form for node.js, so we often skip doing it.
As for between the different libs, I've found that Q has one of the better APIs, but it's also the slowest. https://github.com/kriskowal/q/issues/153
But that's because it uses Object.freeze(), which the js V8 penalizes with a slowdown, when iterating over it. http://stackoverflow.com/questions/8435080/any-performance-b...
In what way is the indented code ridiculous, and why is flatter better?
Conceptually, you still have to think of the callbacks operating the same way in order to properly understand the code. Flattening it out and changing the shape so that it isn't nested doesn't really help change what is going on. Maybe I'm missing the bigger picture.
Promises break that structural linkage: we have the only thing in JS that matters, an object, a first class plain old object, that we can reason with and perform operations on as if it were any other object. It happens to be an object about a future which will one day resolve, but it's just an object.
And because it's an object that can, after it's inception, have handlers added to it, we break the necessary structural linkage that callbacks mandate: we can make callbacks latter, we can condition what callbacks to attach, we can compose or chain more promises after our first promise and put our handler on that... we have a first class thing to work with, not just a function, which expects a fully-readied handler. It defers the need to define handling.
Read more of my comments to get a better sense of why A) I adore promises B) I feel this article is injurous to the case for promises.
Haha I thought the same about the Crockford talk. Can you point me to a non-injurious source?
> you still have to think of the callbacks operating the same way in order to properly understand the code.
It depends on your conception. ;) Maybe it's my Haskell/monad experience, but to me, there's a difference between "here's the control flow between these bits of computation" and "where does this level of nesting end, again?"
See Domenic Denicola's comment at the bottom of the article, and his excellent "You're Missing the Point of Promises" post: https://gist.github.com/3889970
All in all, I find promises to be pretty pointless in javascript. Until ES6, that is. I also experimented with the "yield" expression in google's traceur compiler, but they were still working out their issues last time I tried.
For example, one of the great things about high level programming languages is that you can write composable expressions such as
f(g() + h())
but you can't do that if f and g are written in CPS style, since then you need to give an explicit names to all the intermediate "registers" used in the computation as well as baking down an specific order of evaluation for things g(function(a){
return h(function(b){
return f(a + b)
})
})
> Also, if your pyramid is too deep, chances are you need to extract some of it into functions.This sounds like that "if your method is more then 15 lines you should split it into subfunctions". I never liked this line of reasoning because the complexity (number of possible interactions) in a module increases quadratically with the number of functions in it. You fight this complexity by only breaking down a function on "natural" boundaries dictated by encapsulation and reuse, rather then by code size.
There is also LiveScript which has backcalls:
x <- map _, [1 to 3]
x * 2
# => [2, 4, 6]
data <-! $.get 'ajaxtest'
$ \.result .html data
processed <-! $.get 'ajaxprocess', data
$ \.result .append processed
I think the LiveScript syntax is awesome.