1

I have read every article on $q out there but somehow I am unable to grasp it. For example take the best article I found. I get as far as:

var myFirstDeferred = $q.defer(); //Actually I don't even get this far

A deferred represents the result of an asynchronic operation. It exposes an interface that can be used for signaling the state and the result of the operation it represents. It also provides a way to get the associated promise instance.

What's a 'deferred'? How is it different from a promise? Then we get to this:

async(function(value) {  
    myFirstDeferred.resolve(value);
}, function(errorReason) {
    myFirstDeferred.reject(errorReason);
});

I have NO idea what this is doing. I want to stress that I understand async. I understand the promise structure. For example I know exactly what the code below is doing:

$http.get(url)
    .then(function(result){returnresult}
     ,function(error){return error})

But what are we doing with the deferred in the object above? Why even have the deferred at all? Why not just the then block?

Edit: I want to stress that I went through a ton of replies here, as well as the articles. I thought the point of $q was the force the execution of an async call (kind of like "await" in c#) and then perform some code after. I really don't understand how it does that. I do get how the .all command works when waiting for multiple async operations in this example, but not with one.

Edit: This edit is in response to the duplicate suggestion - I disagree with the notion. For one, this question is more focused and limited in scope. In addition, the answer accepted here clarifies far better (imo) than the wide-net answer in the other q.

Community
  • 1
  • 1
VSO
  • 11,546
  • 25
  • 99
  • 187
  • It's nothing more than any other promise... this is just Angular's kind of awkward syntax. Do you know the standard syntax for creating promises? `return new Promise(function(resolve, reject) { //etc` Angular is having you call that function and returning an object with `resolve` and `reject` instead of the standard way: wrap everything in the new Promise constructor which received `resolve` and `reject` as params. – m59 Sep 10 '15 at 02:59
  • possible duplicate of [What are the differences between Deferred, Promise and Future in Javascript?](http://stackoverflow.com/questions/6801283/what-are-the-differences-between-deferred-promise-and-future-in-javascript) – Claies Sep 10 '15 at 02:59

2 Answers2

2

Typically you don't have to use a deferred explicitly. If you find yourself using $q.defer you should question why you are not using the promise interface directly. See the bluebird documentation for a description of why. $http and many other libraries use deferreds internally and return promises from the methods they expose so using deferreds on top of this is unnecessary.

That being said, deferreds can be useful and understanding them is important. Typically, deferreds have two methods: .reject and .resolve. Honestly there could be one method that you could use to mark the result of an asynchronous operation:

.reject -> the asynchronous operation failed or could not complete
.resolve -> the asynchronous operation completed successfully

When a deferred is completed, it triggers the promise callbacks.

You need to use $q.defer or deferreds when dealing with operations that are asynchronous but do not have a built in promise interface such as timers:

var dfd = $q.defer();

$timeout(function () {
    // this is asynchronous

    // it completed successfully
    dfd.resolve("some value");
}, 500);

dfd.promise.then(function (value) {
    assert.equal(value, "some value");
});

Rather than using deferreds as an object interface, Angular allows you to use these destructured as function arguments to $q

Rewriting the above:

var promise = $q(function (resolve) {
    $timeout(function () {
        resolve("some value");
    }, 500);
});
promise.then(function (value) {
    assert.equal(value, "some value");
});
Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • So, I am going to ask this in a 2 year old manner (at which level I would be more than happy to understand it). Essentially, you make some object that you say something will eventually call "resolve" or "reject" on, i.e. "var someValue = $q.defer(); Then from ANYWHERE (theoretically, though usually from async functions) in your code (probably that can see the scope), you call someValue.resolve('someArgument'). Once you make this call your someValue.promise gets resolved/rejected? Still going through the rewriting part. – VSO Sep 10 '15 at 03:13
  • 1
    @VSO exactly right. It wouldn't necessarily have to be asynchronous. Also it's not exactly from _anywhere_ ... obviously you have to have access to the `someValue` variable – Explosion Pills Sep 10 '15 at 03:16
  • Hmm, i think I get it. At least, I get it far more than I did before. Will have to think about the rewrite, but this clears up a lot. Genuinely, thank you very much. – VSO Sep 10 '15 at 03:21
1

A deferred object is just a subset of a promise that only gives you .reject and .resolve, which prevents the outside world from doing anyting else with it. If you can't return a promise (like when using a library built on callbacks, not promises), make a deferred and manually reject or resolve it.

deferred.reject and deferred.resolve only matter when you return the deferred. Basically:

somePromise().then( function() {
    var deferred = q.defered();

    someFunctionThatHasCallback( function() {
        deferred.resolve();
    });

    return defererd;
}).then( function() {
    console.log( 'I wait for deferred.resolve' );
});

If your functions return promises, you don't need deferred, because promises are chainable by returning inside .then

somePromise().then( function() {
    return someFunctionThatReturnsPromise();
}).then( function() {
    console.log( 'I wait for promise to resolve' );
});
Andy Ray
  • 30,372
  • 14
  • 101
  • 138