问题
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 then
s 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