Terence Chow
Terence Chow

Reputation: 11153

$q.all not working as expected?

Can someone please explain to me why my q.all is not working?

I have 5 promises that download images to blob files. I have another 5 promises which upload these blobs to the servers I use. I use a backend-as-a-service Quickblox so the callback on a successful upload provides the Amazon AWS url link. I need to take all these links and upload them to my servers so that I know which user is associated with which images.

The 5 downloads and uploads seem to work, but the upload to the url is not working. Before each resolve happens in the uploads function, the callback sets $scope.amazon_urls = to the callback url provided. Therefore when Q.all.runs, I expect all $scope.amazon_urls to exist. This however is not the case. What is going on?

Order of functions is: 1)

Here is the function to upload urls. I've commented the sections that I'm thinking is causing issues.

function uploadURLs(scope,principal){

QB.data.list(className,{user_id:principal.user_id},function(err,res){
    if (err){
      console.log(err);
      return err;
    } else {
      console.log(res)
    var data = {
      _id: res.items[0]._id,
      image1: scope.amazon_urls[0],  // Accessing these values should all be set after q.all
      image2: scope.amazon_urls[1],  // A null value indicates that 
      image3: scope.amazon_urls[2],  //the callback function has not set it yet
      image4: scope.amazon_urls[3],  // however this function should occur after q.all
      image5: scope.amazon_urls[4]   // so shouldn't this all be set already?
  }
  QB.data.update(className,data,function(e,r){
    if (e){
      console.log(e);
      return e;
    } else {
     console.log(r);
      return r;    
    }
  });
  }
});
}

Here is the button that executes the download / upload promises and pushes them into an array $scope.promises

$scope.selectPictureForProfile = function(t){
var deferred = $q.defer();
var qbdeferred = $q.defer();
var promise = xhrPromise(deferred,t.photo,$scope,$scope.currently_selected).then(function(blob){
    QBCreateAndUploadPromise(qbdeferred,$scope,$scope.currently_selected,blob);
  });
$scope.promises.push(promise);

}

Here is the button that runs q.all. Once everything is resolved,

$scope.save_photos = function(){

$q.all($scope.promises).then(function(response){
    uploadURLs($scope,principal);   // this seems to execute before last promise
});

}

Here is the function to download images...

function xhrPromise(deferred,url,scope,i){
  var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onload = function(e) {
      if (this.status == 200) {
        var myBlob = this.response;
        scope.image_blobs[i] = myBlob;
        deferred.resolve(myBlob);
      } else {
        deferred.reject("");
      }
    };
  xhr.send(); 
  return deferred.promise;
}

Here is the function to upload images...

function QBCreateAndUploadPromise(deferred,scope,i,blob){
  QB.content.createAndUpload({'file':blob,'name':"profilepics.jpg", 'type':"image/jpeg", 'public': true },function(e,r){
        if(e){
          deferred.reject("error");
        } else {
          scope.amazon_urls[i]= "http://qbprod.s3.amazonaws.com/" + r.uid;
          deferred.resolve("http://qbprod.s3.amazonaws.com/"+ r.uid); 
        }
 });
 return deferred.promise;
}

Upvotes: 1

Views: 1620

Answers (1)

Terence Chow
Terence Chow

Reputation: 11153

After much difficulty it turns out that q.all was firing right after my first promises were fired.

However since I chained that first set of promises I was expecting q.all to fire after the second set of promises.

In order to get them to fire after the first set I had to create an array of promises for the first set then use

.then(function(){$q.all(second_set_of_promises).then(third_final_set_of_promises)});

In this way, the third set of promises only fires after the second set is complete and the second set only fires when the first set is complete.

Upvotes: 1

Related Questions