Angular js 承诺链接
Angular js promises chaining
过去两天我一直在努力弄清楚承诺,到目前为止我已经明白了。任何引导方向都会很棒,因为我认为我自己感到困惑。
所以这是我的服务,它必须 运行 以便在图像捕获后超时以便服务器更新:
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;
},
到处都是...
P.S。我以建筑为生
$http
已经返回一个承诺,所以调用服务时不需要使用 $q.defer()
。相反,我建议将所有 $http
请求放在单独的 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
}
});
在您的控制器中,您现在可以使用 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
})
});
请注意,我并没有实际实现上面的代码,但应该为您提供一个大纲。
首先,@sjokkogutten 的回答是必经之路。将您的业务逻辑放在尽可能高的位置(例如在服务中)可以使应用程序更易于维护和测试。
请不要使用$http.get(...).then(onSuccess, onError)
的第二个参数,因为它不可链接。
$http.get(...).then(onSuccess).except(onError)
是更好的模式。
关于 promises 的一些注意事项
当您链接承诺时,每个 then
回调都会收到前一个回调的承诺。
$http.get(...)
.then(function (result) {
return 'getCameraDirectory'; // Or $q.resolve('getCameraDirective'), doesn't matter
})
.then(function (result2) {
// result2 is 'getCameraDirectory'
});
使用 promises 时,始终 return 很重要!忘记一个 return 很容易,您的承诺链最终将解析为 undefined
.
您的示例链接了一些方法,但这些方法没有 return 任何东西。这意味着下一个链接的回调不接收参数。最后,saveMedia()
没有 returning 任何东西,所以整个承诺链解析为 undefined
.
请注意,整个示例中只有一个 return 语句。
拒绝
假设在您的一个回调中,您想根据条件打破链条。
您需要拒绝承诺。所有直接链接的 then
不再被调用。
$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
});
过去两天我一直在努力弄清楚承诺,到目前为止我已经明白了。任何引导方向都会很棒,因为我认为我自己感到困惑。
所以这是我的服务,它必须 运行 以便在图像捕获后超时以便服务器更新:
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;
},
到处都是...
P.S。我以建筑为生
$http
已经返回一个承诺,所以调用服务时不需要使用 $q.defer()
。相反,我建议将所有 $http
请求放在单独的 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
}
});
在您的控制器中,您现在可以使用 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
})
});
请注意,我并没有实际实现上面的代码,但应该为您提供一个大纲。
首先,@sjokkogutten 的回答是必经之路。将您的业务逻辑放在尽可能高的位置(例如在服务中)可以使应用程序更易于维护和测试。
请不要使用$http.get(...).then(onSuccess, onError)
的第二个参数,因为它不可链接。
$http.get(...).then(onSuccess).except(onError)
是更好的模式。
关于 promises 的一些注意事项
当您链接承诺时,每个 then
回调都会收到前一个回调的承诺。
$http.get(...)
.then(function (result) {
return 'getCameraDirectory'; // Or $q.resolve('getCameraDirective'), doesn't matter
})
.then(function (result2) {
// result2 is 'getCameraDirectory'
});
使用 promises 时,始终 return 很重要!忘记一个 return 很容易,您的承诺链最终将解析为 undefined
.
您的示例链接了一些方法,但这些方法没有 return 任何东西。这意味着下一个链接的回调不接收参数。最后,saveMedia()
没有 returning 任何东西,所以整个承诺链解析为 undefined
.
请注意,整个示例中只有一个 return 语句。
拒绝
假设在您的一个回调中,您想根据条件打破链条。
您需要拒绝承诺。所有直接链接的 then
不再被调用。
$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
});