Q promises chaining to do things in correct order

2019-09-10 15:29发布

问题:

I have a asynchronous function that needs to be called multiple times in the correct order. It's about uploading images to a server but like I said the images should be uploaded in the correct order.

My function looks like this:

  function uploadImage(sku,fileName) {
    console.log("Uploading image for sku="+sku+", imageName="+fileName);

    var deferred = Q.defer();

    var readStream = fs.createReadStream(rootPath+'/data/'+sku+"/"+fileName);
    var req = request.post('http://localhost:3000/'+sku+'/upload/'+fileName);

    readStream.pipe(req);

    req.on('end', function() {
      console.log("Image imageName="+fileName+" uploaded successfully.");
      db.updateLastUploadedImage(sku,fileName).then(function (res) {
        if(res) {
          console.log("Table watches for sku="+sku+" updated.");
          deferred.resolve(sku);
        }
      });
    });

    req.on('error',function(err) {
      deferred.reject(err);
    });

    return deferred.promise;
  }

I tried to bring it on with chaining the promises like documented in https://github.com/kriskowal/q but it's not working well. Somehow I do not come to the "then" block.

So I tried to make a recursive function but it also does not go inside the "then" block of the function call.

Only this method works but its not running through the correct order.

function uploadImages(sku) {
    var promises = [];

    for(var x=0; x<10; x++) {
      promises.push(uploadImage(sku,(x+1)+".jpg")));
    }

    return Q.all(promises).then(function (res) {
      return sku;
    });
}

My recursive solution looks like this:

function uploadImages(sku,current,max) {
    var deferred = Q.defer();

    if(current<=max) {
      uploadImage(sku,current+'.jpg').then(function (res) {
        if(res) {
          uploadImages(sku,current+1,max);
        }
      }, function (err) {
        deferred.reject();
      });
    } else {
      deferred.resolve(sku);
    }

    return deferred.promise;
 }

What I'm looking for is something like this (but thats not the way to implement):

 return uploadImage(sku,"1.jpg").then(function(res) {
      return uploadImage(sku,"2.jpg").then(function(res) {
        return uploadImage(sku,"3.jpg").then(function(res) {
          return uploadImage(sku,"4.jpg").then(function(res) {
            return uploadImage(sku,"5.jpg").then(function(res) {
              return uploadImage(sku,"6.jpg").then(function(res) {
                return uploadImage(sku,"7.jpg").then(function(res) {
                  return uploadImage(sku,"8.jpg").then(function(res) {
                    return uploadImage(sku,"9.jpg").then(function(res) {
                      return uploadImage(sku,"10.jpg").then(function(res) {
                        return sku;
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });

So what is the best practice for my purpose?

回答1:

There is no concept of "correct order" for async calls because they are just that -- asynchronous and they can end at any point.

In your the callback in Q.all(promises).then(...) you should have the responses in the order that you made them, but the order of your console logs may not be in the same order due their asynchronous nature.


In your case, you can probably do it recursively:

function uploadFiles(sku, current, max) {
     return uploadImage(sku, current + '.jpg').then(function (sku) {
          if (current > max) { return sku; }

          return uploadFiles(sku, current + 1, max);
     });
}

// use it
uploadFiles('SOME_SKU', 1, 10).then(function (sku) {
    // ALL DONE!
});


回答2:

Try to catch exceptions from the promise.

return Q.all(promises).then(function (res) {
  return sku;
})
.catch(function (error) {
    // Handle any error from all above steps
});