Angular js promises chaining

…衆ロ難τιáo~ 提交于 2020-01-17 03:10:47

问题


Ive been trying to figure out promises for the last two days and i gotten this so far. Any guided direction would be great as i think i confused my self.

So this is my service, it has to run in order with a timeout after image capture for the server to update:

returnImage: function() {
      var results = {};
   function getCameraDirectory(){
     // Get directory infomation from camera
     var list = [];
     deferred = $q.defer();
     console.log("getCameraDirectory");
     $http.get(BASE_URL + IMAGE_URL).then(
     function(response){
       $("<div>").html(response.data).find('a').each(function() {
         var text = $(this).text();
         if(text !== 'Remove'){
         list.push(text);
       }
       });
        if(results.hasOwnProperty("medialist")){
          results["filelist"] = list.diff(results["medialist"]);
        }else{
          results["medialist"] = list;
        }
        deferred.resolve('getCameraDirectory')
     },
     function(error){
       console.log(error);
        deferred.reject(error);
     });
   }

   function setCameraMode(){
     // sets the camera mode to picture, multi-image, video
     deferred = $q.defer();
     console.log("setCameraMode")
     $http.get(BASE_URL + '?custom=1&cmd=3001&par=0').then(
     function(response){
       if(response.status === 200){
        results["mode"] = 'image';
       deferred.resolve('setCameraMode');
     }else{
       deferred.reject("Counldnt change Camera mode");
     }
     },
     function(error){
       console.log(error);
        deferred.reject(error);
     });
   }

   function captureMedia(){
     // starts the capture process picture, multi-image, video
     console.log("captureMedia")
      deferred = $q.defer();
     $http.get(BASE_URL + '?custom=1&cmd=1001').then(
     function(response){
       if(response.status === 200){
        results["date"] = Date.now();
       deferred.resolve('captureMedia');
     }else{
       deferred.reject("Counldnt insiate image capture");
     }
     },
     function(error){
       console.log("error");
        deferred.reject(error);
     });
   }

   function saveMedia(){
     console.log('saveMedia');
     deferred = $q.defer();
     console.log(results["filelist"]);
     var mediaName = results["filelist"];
     var url = BASE_URL + IMAGE_URL + mediaName;
     var targetPath = cordova.file.externalRootDirectory + 'photoboothinabox/' + mediaName;
     var filename = targetPath.split("/").pop();
     $cordovaFileTransfer.download(url, targetPath, {}, true).then(function (response) {
         deferred.resolve('saveMedia');
         console.log('Success');
     }, function (error) {
         deferred.reject("Counldnt save to disk");
         console.log('Error');
     }, function (progress) {
         // PROGRESS HANDLING GOES HERE
         console.log(progress)
     });
   }
   function test(){
     console.log("past it")
   }

    var deferred= $q.defer(),
    promise = deferred.promise;

      promise.then(getCameraDirectory())
            .then(setCameraMode())
            .then(captureMedia())
            .then(getCameraDirectory())
            .then(saveMedia());
  return promise;

},

It just goes all over the place...

P.S. I work construction for a living


回答1:


$http is already returning a promise, so there is no need to use $q.defer() when calling a service. Instead, I would recommend placing all your $http request in a separate service/service:

app.factory('DataService', function($http, $cordovaFileTransfer) {
  var getCameraDirectory = function() {
    return $http.json("/api/...") // returns a promise
  };

 var setCameraMode= function() {
    return $http.json("/api/...") 
  };

 var getCameraDirectory = function() {
    return $http.json("/api/...") 
  };

 var captureMedia = function() {
    return $http.json("/api/...") 
  };

 var saveMedia = function() {
    return  $cordovaFileTransfer.download(url, targetPath, options, trustHosts) // I am not sure, but I am assuming that $cordovaFileTransfer.download() is returning a promise. 
  };

  return {
    getCameraDirectory: getCameraDirectory,
    setCameraMode: setCameraMode,
    captureMedia: captureMedia,
    saveMedia: saveMedia
  }
});

In your controller, you can now resolve your promises using then

myApp.controller('MyController', function ($scope, DataService) {     
    DataService.getCameraDirectory().then(
      function(){ //resolve getCameraDirectory 
        // getCameraDirectory successcallback
      },
      function(){
        // getCameraDirectory errorcallback
      }).then( // resolve setCameraMode 
        function(){
          // setCameraMode successcallback
        },
        function(){
          // setCameraMode errorcallback
        }).then( // resolve captureMedia 
          function(){
            // captureMedia successcallback
          },
          function(){
            // captureMedia errorcallback
          }).then(// resolve saveMedia
            function(){
              // saveMedia successcallback
            },
            function(){
              // saveMedia errorcallback
            })   
});

Note that I have not actually implemented the above code, but should provide you with an outline.




回答2:


First of all, @sjokkogutten's answer is the way to go for. Putting your business logic as high as possible (eg. in services) makes the app more maintainable and testable.

Please do not use the second parameter of $http.get(...).then(onSuccess, onError) because it is not chainable.

$http.get(...).then(onSuccess).except(onError) is a better pattern.

A few notes about promises

When you are chaining promises, each then callback receives the promise from the previous one.

$http.get(...)
  .then(function (result) {
    return 'getCameraDirectory'; // Or $q.resolve('getCameraDirective'), doesn't matter
  })
  .then(function (result2) {
    // result2 is 'getCameraDirectory'
  });

When working with promises, it is important to always return something! It is easy to forget one return and your promise chain will eventually resolve to undefined.

Your example chains some methods, but these methods do not return anything. This means that the next chained callback does not receive parameters. At last, saveMedia() isn't returning anything, so the whole promise chain resolves to undefined.

Note that you have only one return statement in the whole example.

Rejecting

Suppose in one of your callbacks you want to break the chain based on a condition.

You need to reject the promise. All directly chained thens are not called anymore.

$http.get(...)
  .then(function (result) {
    if (result.length > 0) {
      return result;
    } else {
      return $q.reject('result is empty'); // or throwing error
    }
  })
  .then(function (result2) {
    // result2 is non empty!
  })
  .catch(function (message) {
    // this callback is called when result is empty OR when the $http.get call rejects (eg. returns 404)
    // Return something if you want to chain further
    return 'Back on track';
  })
    .then(function (result3) {
      // result3 === 'Back on track'
      // This callback is only called when coming from `except`
    })
    .catch(function (message2) {
      // This callback is called when previous 'except' or 'then' is rejecting
    });


来源:https://stackoverflow.com/questions/35848927/angular-js-promises-chaining

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!