我有一个使用angular和cordova的离子(v1)项目。
我循环遍历一组文件名,并将每个文件数据附加到FormData
对象中,该对象必须上传到服务器。
为了读取文件数据,Cordova/HTML5
提供了一些异步的方法。我正在使用angular的$q
承诺来调用这些方法。
然后我想使用$q.all
等待所有承诺解决并开始上传。
但是承诺永远不会得到解决,$q.all(promises).then
中解析的功能块永远不会被调用。
奇怪的是,如果我拒绝承诺而不是使用deferred.reject
解析承诺,则会调用$q.all
的错误方法。
我如何解决承诺?
以下是代码:
//Inside a controller
var promises = [];
for (var key in $scope.rArray) {
if ($scope.rArray.hasOwnProperty(key)) {
var deferred = $q.defer();
var tmpFile = $scope.rArray[key];
var i = cordova.file.externalRootDirectory + "/" + tmpFile;
window.resolveLocalFileSystemURL(i, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
console.log('onloadend callled');
var fileBlob = new Blob([this.result], { type:file.type});
fd.append('file', fileBlob,file.name);
deferred.resolve(fd); //if reject here it is reflected
//$rootScope.$apply(). tried this too
};
reader.readAsArrayBuffer(file);
}, function(e) {
console.log('error getting file', e);
deferred.reject(e);
});
}, function(e) {
console.log('Error resolving fs url', e);
deferred.reject(e);
});
promises.push(deferred.promise);
}
};
$q.all(promises).then(function (dataAr) {
console.log('promises resolved..'); //NEVER CALLED
var request = new XMLHttpRequest();
request.open('POST', ENV.baseUrl+"/st/st");
request.send(fd);
}, function errorfn(err) {
console.error(JSON.stringify(err));
})
答案 0 :(得分:1)
问题是public class EditProfile extends AppCompatActivity
{
private TextView originTV;
private EditText descriptionET;
private ImageView cameraIV, mainIV;
private Button doneButton;
private static final String EDIT_PROFILE = "EDIT_PROFILE";
private UpdateUserString updateUserString;
private int PLACE_AUTOCOMPLETE_REQUEST_CODE = 20;
private User localActivityUser;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_16e_profile_edit);
bindActivity();
}
private void bindActivity()
{
localActivityUser = Global_Class.getInstance().getValue().user;
originTV = (TextView) findViewById(R.id.editProfile_originTV);
descriptionET = (EditText) findViewById(R.id.editProfile_descriptionET);
cameraIV = (ImageView) findViewById(R.id.editProfile_cameraIV);
mainIV = (ImageView) findViewById(R.id.editProfile_imageIV);
doneButton = (Button) findViewById(R.id.editProfile_doneButton);
doneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!localActivityUser.getDescription().equals(descriptionET.getText().toString()))
{
//Call api to update my backend.
UpdateUserStringAsyncTask updateUserStringAsyncTask = new UpdateUserStringAsyncTask("description",descriptionET.getText().toString());
updateUserStringAsyncTask.execute();
}
else if(!localActivityUser.getOrigin().equals(originTV.getText()))
{
//Call api to update my backend
UpdateUserStringAsyncTask updateUserStringAsyncTask = new UpdateUserStringAsyncTask("origin",originTV.getText().toString());
updateUserStringAsyncTask.execute();
}
}
});
}
是最后一个,当任何var deferred
函数的任何回调被调用时
所以,只有一个承诺可以被解决或拒绝
使用Promise.all,一次拒绝就足以拒绝Promise.all返回的Promise - 但所有承诺必须解决Promise.all才能解决
我最初在你的代码中玩弄了一个闭包的想法 - 但是使用常见的JS方法似乎是一个更好的解决方案 - Object.keys和Array#map
resolveLocalFileSystemURL