11

I am new to angularjs.I saw $q in restful api calls to check the promise. $q.defer() was used to retain the promise object. I read about the promises but I didn't get anything. although I can make the api call without $q, however it is used somewhere in articles.

So I want to know the exact use of $q and difference in making api calls without $q.

Kindly help. thanks

Sachila Ranawaka
  • 39,756
  • 7
  • 56
  • 80
Tejinder Singh
  • 1,070
  • 2
  • 8
  • 24
  • Basically, the main different from real `Promise` is that any `.then()` or `.catch()` from a `$q` instance will automatically be run inside of `$scope.$apply()` for you. – binki Jun 01 '18 at 17:53
  • Not sure this is the same question as the one linked to in the "This question already has answers". That says, "I have this use case. How can `$q` solve it?" This says, "How do I use `$q`?" Too broad? _Maybe_ though I don't think so. It's well answered below. But not the same. – ruffin Aug 13 '20 at 14:48

2 Answers2

31

I think the article I wrote about $q might help you.

Introduction to $q

$q is an angular defined service. It’s the same as new Promise(). But $q takes things to the next level by enhancing additional feature that developers can use to perform complex tasks more simply.

This is a sample for creating a promise using $q

angular.module("app",[])
.controller("ctrl",function($scope,$q){
  var work = "resolve";
  var promise = $q(function(resolve, reject) {
    if (work === "resolve") {
        resolve('response 1!');
    } else {
        reject('Oops... something went wrong');
    }
  }); 
  promise.then(function(data) {
    alert(data)  

  }) 
})

$q.defer()

$q.defer() return the instance of the promise constructor. Once you create a defer object there are following methods and properties that you can access from that object

resolve(value) – resolves the derived promise with the value. If the value is a rejection constructed via $q.reject, the promise will be rejected instead.

reject(reason) – rejects the derived promise with the reason. This is equivalent to resolving it with a rejection constructed via $q.reject.

notify(value) - provides updates on the status of the promise's execution. This may be called multiple times before the promise is either resolved or rejected.

promise – {Promise} – promise object associated with this deferred

See the example

angular.module("app",[])
.controller("ctrl",function($scope,$q){
  var work = "resolve";

  function getData(){
    var obj = $q.defer();

    if (work === "resolve") {
        obj.resolve('response 1!');
    } else {
        obj.reject('Oops... something went wrong');
    }

    return obj.promise;
  } 
  getData().then(function(data) {
    alert(data)  

  }) 
})    

$q.all()

If a user need to send multiple request one shot,then the user can use $q.all() service.

 $q.all([$http.get('data1.json'),$http.get('data2.json')])
      .then(function(response){
        console.log(response[0].data) // data1.json response 
        console.log(response[1].data) // data1.json response 
 })

In here,there are two http request sent simultaneously to two separate JSON files to get data. The response comes as an array and response order is same as the HTTP request order.

$q.race()

$q.race() is very similar to $q.all(). But instead of sending response of each request, it will only return the one request response. Specifically, only return the response of first request that been executed. That does not mean it’s not going to send other requests. All the requests are sending but it's only return the response of the first request that executed.

 $q.race([$http.get('data1.json'),$http.get('data2.json')])
      .then(function(response){
        console.log(response[0].data) // return one response 
 })

In here response can be either data1.Json or data2.json. That's the downfall of using this method. Since its return the response of the first executed request, can’t be sure which request response will resolved by the promise. This method useful for bulk requests which you don’t want to see the response of all the requests

Conclusion

Use $q for constructing promises from non-promise Objects/callbacks, and utilize $q.all() and $q.race() to work with existing promises.

Abhinav
  • 530
  • 8
  • 21
Sachila Ranawaka
  • 39,756
  • 7
  • 56
  • 80
  • 1
    Post your code instead of screenshots. – Mistalis Apr 19 '17 at 12:40
  • 1
    @Mistalis removed the pic – Sachila Ranawaka Apr 19 '17 at 12:51
  • thanks @sachilaranawaka for writing...could you please tell that where should I use the `$q` in angularjs? how can I actually use the promises in `$q`? – Tejinder Singh Apr 19 '17 at 13:17
  • basically, you can use $q to create a new promise (using defer), send multiple requests one shot (using q.all) – Sachila Ranawaka Apr 19 '17 at 13:19
  • okay. but `$http` itself returns a promise. actually my concern is what if i don't use the `$q` service in api call. what would be the impact? please explain – Tejinder Singh Apr 19 '17 at 13:23
  • http return response as promise. so no need to create a custom promise for $http. for single $http call no need to use the $q – Sachila Ranawaka Apr 19 '17 at 13:26
  • ok it means we only need to use `$q` when we have multiple calls and we don't want to block them. for single call we don't have any need to use `$q`. we can achieve this by only using `$http`...am I right? – Tejinder Singh Apr 19 '17 at 13:31
  • $q not only use to send multiple requests. we can create custom promises from it. other parts are right – Sachila Ranawaka Apr 19 '17 at 13:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142087/discussion-between-tejinder-singh-and-sachila-ranawaka). – Tejinder Singh Apr 19 '17 at 13:34
  • @SachilaRanawaka, you meant `console.log(response[1].data) // data2.json response` instead of `console.log(response[1].data) // data1.json response `? – Binod Kalathil Nov 09 '18 at 20:16
  • @SachilaRanawaka let say i have multiple resource and i want to call them in sync manner (call 1 API after getting response of another) how can I do that? i don't have fix number of resource but all should be called 1 at a time in angularjs. How to achieve with $q? Please suggest – Jayesh Dhandha Jul 29 '22 at 05:47
6

I like this question. Because, I too faced this.

This is a service that helps you run functions asynchronously, and use their return values when they are done processing.

Brief Description

Refer example

Promise with $q

Example :

app.service("githubService", function($http, $q) {

    var deferred = $q.defer();

    this.getAccount = function() {
        return $http.get('https://api.github.com/users/haroldrv')
            .then(function(response) {
                // promise is fulfilled
                deferred.resolve(response.data);
                // promise is returned
                return deferred.promise;
            }, function(response) {
                // the following line rejects the promise 
                deferred.reject(response);
                // promise is returned
                return deferred.promise;
            });
    };
});
  • thanks for writing @Veera... i just want to know without using `$q`service means we are making synchronous call to api.. right? – Tejinder Singh Apr 19 '17 at 13:03
  • please refer this for synchronous and asynchronous calls http://stackoverflow.com/questions/5187968/how-should-i-call-3-functions-in-order-to-execute-them-one-after-the-other –  Apr 19 '17 at 13:09