It seems generally that creating deferred objects is now commonly discouraged in favor of using the ES6-style Promise constructor. Does there exist a situation where it would be necessary (or just better somehow) to use a deferred?
For example, on this page, the following example is given as justification for using a deferred:
function delay(ms) {
var deferred = Promise.pending();
setTimeout(function(){
deferred.resolve();
}, ms);
return deferred.promise;
}
However, this could be done just as well with the Promise constructor:
function delay(ms) {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve();
}, ms);
});
}
Native Promises don't have all the built-in methods that deferred has out of the box, for example the method to resolve the promise outside the scope of its constructor (very easy to implement with native Promise, though), and the ability to look at the status of a promise (which is hidden from regular JavaScript on native Promises, though it can be inspected in the dev tools).
The main reason to use deferred today would be backwards compatibility with code that depends on those extra methods. Hard to give a definitive answer to your question without stepping onto opinion territory.
There is no such situation where a deferred is necessary. "Better" is a matter of opinion so I won't address that here.
There's a reason that the ES6 promise specification does not have a deferred object. You simply don't need one. Anything that people used to use a deferred object for can always be done another way that doesn't use a deferred object.
First off, the majority of uses fit very nicely into the promise constructor model. Secondly, any other cases that didn't fit quite so cleanly into that model can still be accomplished with the promise constructor or by starting with a resolved promise and chaining to it.
The main use case I've seen for a deferred is when you want to pass the ability to
resolve()
orreject()
off to some other piece of code other than the code that created the promise. A Deferred made that very easy since you could just pass the deferred object and it had public methods for resolving or rejecting it. But, with a promise, you can also just pass theresolve
and/orreject
methods. Since they are bound to the specific object automatically, you can just pass the function references. And, in other cases, you can just let the other code create their own promise and resolve/reject it themselves and have that operation linked to yours rather than letting them resolve/reject your promise. Is all that quite as clean as passing a deferred object? Mostly a matter of opinion, but neither are very common use cases and all are something that can be accomplished without a separate deferred object.And, as torazaburo points out, letting some external code resolve or reject your promise is a bit of an anti-pattern in its own right. You created the promise - you resolve/reject it. If you want to use external events to decide when to resolve/reject it, then have them notify you (via their own promise or callback) and you can resolve/reject your own promise. Or, have them create their own promise that you can use. That's really the desired model. Or, let them chain onto your promise so that the end result is gated by when their operation is done.
If one was used to coding with the deferred object (say with a jQuery deferred), it might take a little getting used to coding without it, but after a little while you just start to think differently and it starts to come natural to just use the promise constructor.
Once you promisify the sphere of async operations that you use in any given application, it's pretty rare that you ever even need to create your own promises any more because you are mostly just building off promises that the async functions you call are already creating or using flow control operations like
Promise.all()
which create uber promises for you.This is the main point of anti-patterns. Use the promises that are already created for you rather than manually create more. Chain them. Return promises from
.then()
handlers to link async operations under logic control.Of course, there are existing async operations that don't return promises for which somebody needs to create a promise, but that should be done in a promisify layer somewhere outside the purvey of your main coding logic and done only once for that operation and then code that calls the async operation should be able to just use the returned promises.