M07*_*M07 4 web-services promise sequential angularjs
我想知道如何使用AngularJS进行顺序Web服务调用?为了简化,当我们得到第一个web服务的结果时,我们称之为第二个.我已经找到了解决方案,但我并不喜欢它.我认为必须有更好的解决方案,这就是我发布问题的原因.这是我的代码(它有效).
var uploadFile = function(file) {
szUrl = globalServ.datas.szUrl+"transactions/"+globalServ.transactionId+"/file";
var postData = {};
postData['name'] = "MyFile"+file;
postData['file'] = $scope.wsFiles[file];
$http({
method: 'POST',
url:szUrl,
headers: {'Content-Type': false, 'Authorization': globalServ.make_base_auth()},
transformRequest: formDataObject,
data:postData,
}).success(function(response) {
$scope.qFiles[file].resolve(file);//This will allow to call "then" method
}).error(function (data, status, headers, config) {
$scope.errorMsg = globalServ.getErrorMsg(status, data);
$scope.filesAdded = false;
});
}
$scope.uploadFiles = function() {
delete $scope.errorStatus;
$scope.qFiles = [];
$scope.uploadOver = false;
for(file in $scope.wsFiles) {
var q1 = $q.defer();
q1.promise.then(function(curFile) {
if(curFile < $scope.wsFiles.length - 1) {
uploadFile(curFile+1);
} else {
$scope.uploadOver = true;//We uploaded all contracts so now can stop to show loading button
}
});
$scope.qFiles.push(q1);
}
uploadFile(0);//We start to upload contracts
};
Run Code Online (Sandbox Code Playgroud)
欢迎所有关键人物.先感谢您.
首先接受如果你要使用promises,你想在任何地方使用它们.他们已经提供了许多你想要手工创建的结构.此外,$scope除非绝对必要,否则尽量避免向(或任何其他全局)添加内容.构建所有实用程序函数,使它们独立于范围和任何视图更新等.
接下来要做的就是让uploadFile回报成为承诺.我们还希望它不使用$ scope,而是将所需的所有信息作为参数.因此我建议如下:
function uploadFile(file) {
szUrl = globalServ.datas.szUrl+"transactions/"+globalServ.transactionId+"/file";
var postData = {};
postData['name'] = "MyFile"+file.name;
postData['file'] = file.data;
return $http({ // <--------------------------- return the promise here
method: 'POST',
url:szUrl,
headers: {'Content-Type': false, 'Authorization': globalServ.make_base_auth()},
transformRequest: formDataObject,
data:postData,
}).then(function onSuccess(response) { //<--- `.then` transforms the promise here
return file
}, function onError(response) {
throw globalServ.getErrorMsg(response.status, response.data);
});
}
Run Code Online (Sandbox Code Playgroud)
其中file是表单的对象 {name: 'file name', data: 'contents of file post'}
对于上传文件,我们必须决定是要将它们并行还是按顺序上传.并行通常会更快,但会使用更多资源(内存,带宽等).如果你需要同时做很多其他事情,你可能想要连续完成它们.您可能还想选择上传的第三个选项(此处未涵盖),并且最多可以并行显示最多5个选项.
无论哪种方式,我们将创建一个接受一组file对象并上传它们的函数,然后返回一个在操作完成时解析的promise,如果失败则拒绝.
要并行执行,我们只需上传每个文件,然后使用$q.all等待所有上传完成.
function uploadFilesParallel(files) {
var uploads = []
for(var i = 0; i < files.length; i++) {
uploads.push(uploadFile(files[i]))
}
return $q.all(uploads)
}
Run Code Online (Sandbox Code Playgroud)
顺序上传只是稍微复杂一点.原则上我们需要做的是让每个操作在开始之前等待前一个操作完成.为此,我们首先创建一个由已解析的promise表示的虚拟初始操作.然后,我们通过循环跟踪先前的操作,以便我们可以在上载之前始终等待上一个操作.
function uploadFilesSequential(files) {
var previous = $q.when(null) //initial start promise that's already resolved
for(var i = 0; i < files.length; i++) {
(function (i) {
previous = previous.then(function () { //wait for previous operation
return uploadFile(files[i])
})
}(i)) //create a fresh scope for i as the `then` handler is asynchronous
}
return previous
}
Run Code Online (Sandbox Code Playgroud)
最后你附加到范围的原始uploadFiles操作.此时,您可以执行所有必要的操作来更新视图.请注意在此之前我没有触及任何全局变量.这样做的原因是为了确保多次调用uploadFilesSequential或uploadFilesParallel不会发生冲突并导致问题.
我没有对以下功能做出同样的保证.如果多次并行调用它,多个操作可能会导致奇怪的行为.
$scope.uploadFiles = function (parallel) {
delete $scope.errorStatus;
$scope.uploadOver = false;
var files = [];
for(file in $scope.wsFiles) {
files.push({
name: file,
data: $scope.wsFiles[file]
})
}
var uploadOperation
if (parallel) {
uploadOperation = uploadFilesParallel(files)
} else {
uploadOperation = uploadFilesSequential(files)
}
uploadOperation
.then(function(file) {
$scope.uploadOver = true;
}, function (err) {
$scope.errorMsg = err;
$scope.filesAdded = false;
});
};
Run Code Online (Sandbox Code Playgroud)
显然,如果您总是使用并行或始终使用顺序上传,那么您可以稍微简化一下.注意这样做是多么简单,我们所要做的就是处理视图逻辑和实际的实现,uploadFilesSequential或者uploadFilesParallel完全隐藏在我们身上.正是这种封装对于使大型系统编程成为必要.
未来的JavaScript版本即将推出(EcmaScript 6),这将使顺序版本变得更加容易.您将能够重写它大致如下:
var uploadFilesSequential = Q.async(function* (files) {
for(var i = 0; i < files.length; i++) {
yield uploadFile(files[i])
}
})
Run Code Online (Sandbox Code Playgroud)
哪个yield是等待承诺解决的特殊关键字.不幸的是,它可能还需要几年才能在真实世界的代码中使用,以便在浏览器中运行.