As far as $q
promises go, there isn't a huge behavioral difference in one vs. the other. The main benefit of the second approach is that it uses the same style as native promises, and it nicely contains the logic for resolving the promise instead of having a loose deferred dangling around (this is probably one of the reasons why native promises went with the latter style).
I had mistakenly said that the second approach will catch synchronous errors in the passed in function and convert them into a rejected promise. This is true for native promises, Q promises, Bluebird promises, and possibly others, but it is not true for $q()
. $q
will just treat the error as an uncaught error and log it to the console.
Here is an example, using Bluebird promises, of what I was describing. It's a great reason to use the latter style if you are using promises other than $q
:
function queryValue(callback) {
throw new Error("Not implemented yet!!!");
}
function makeConstructorPromise() {
return new Promise(function(resolve) {
queryValue(function(value) {
resolve(value);
});
});
}
function makeDeferredPromise() {
let deferred = Promise.defer();
queryValue(function(value) {
deferred.resolve(value);
});
return deferred.promise;
}
makeConstructorPromise()
.catch(function(error) {
console.error('caught the constructed promise error!', error);
});
makeDeferredPromise()
.catch(function(error) {
// not caught
console.error('caught the deferred promise error!', error);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.1/bluebird.min.js"></script>
The deferred approach is old-fashioned and may have practical applications in very specific cases, but 99% of the time, the constructor approach is the way to go.
It is safer (in most promise implementations) and is consistent with the way ES6 promises work.