我创建了一个带有拖放的文件上传表单,它在已删除的文件夹上递归迭代并上传文件和文件夹,并将它们添加到JSTree实例。
这是drop call
function drop(evt){
evt.stopPropagation();
evt.preventDefault();
//get selected node (created by jsTree)
var parent_id = $('#treeContainer').jstree('get_selected').attr('data-attr-itemid');
var theNodeId = $('#treeContainer').jstree('get_selected').attr('id');
for (var i=0; i<items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
traverseFileTree2(item,parent_id,theNodeId);
}
}
//THIS RUNS BEFORE RECUSIVE FUNCTION IS COMPLETED
addFilesToUploadQueue(filesToQueue);
}
这里是递归遍历函数
var filesToQueue = [];
function traverseFileTree2(item, parent_id, theNodeId, path) {
if (item.isFile) {
item.file(function(file){
//add parent id, and adds to array to be queued for upload
file.parent_id = parent_id;
filesToQueue.push(file);
})
return;
}
else if (item.isDirectory) {
var dirName = item.name;
var url = '<?php echo $this->Html->url(array('controller'=>'nodes', 'action'=>'addchild'));?>';
var data = {'parent_id':parent_id, 'name':dirName, 'type':'Directory'};
$.post(url,data,function(result){
//adds directory node to tree
$("#treeContainer").jstree('open_node','#'+theNodeId);
$("#treeContainer").jstree('create', '#'+theNodeId, 'last', result,null,true);
parent_id = result["attr"]["data-attr-itemid"];
theNodeId = result["attr"]["id"];
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
for (var i=0; i<entries.length; i++) {
traverseFileTree2(entries[i], parent_id, theNodeId, path + item.name + "/");
}
});
}, 'json');
}
}
我的问题是函数addFilesToUploadQueue(filesToQueue)
在递归异步函数traverseFileTree2
完成之前运行。如果可以使用promises完成,我宁愿不使用回调。
答案 0 :(得分:2)
这绝对是你可以用promises攻击的问题。
traverseFileTree2()
以便始终返回promise / deferred,即使您实际上没有异步启动任何内容。
$.when()
等待他们全部完成,然后再与他们合作。traverseFileTree2()
)并再次使用$.when()
将它们组合成一个承诺,当所有承诺都“完成”时结束了,汇总了他们的文件列表。 (没有共享filesToQueue
变量,它是所有返回值。)addFilesToUploadQueue()
以便在这个巨大的最后承诺成功时调用,将承诺的文件返回数据转移到队列这是一个 UNTESTED 重写,但即使它的错误也足以让我们了解这个想法:
function drop(evt){
evt.stopPropagation();
evt.preventDefault();
//get selected node (created by jsTree)
var parent_id = $('#treeContainer').jstree('get_selected').attr('data-attr-itemid');
var theNodeId = $('#treeContainer').jstree('get_selected').attr('id');
var promises = [];
for (var i=0; i<items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
promises.push(traverseFileTree2(item,parent_id,theNodeId));
}
}
$.when(promises).then(function(filesToQueue){
addFilesToUploadQueue(filesToQueue);
});
}
和
function traverseFileTree2(item, parent_id, theNodeId, path) {
var ret = $.Deferred();
if (item.isFile) {
var files = [];
// What is .file()?? I'm assuming it's synchronous right now
item.file(function(file){
//add parent id, and adds to array to be queued for upload
file.parent_id = parent_id;
files.push(file);
});
ret.resolve(files)
} else if (item.isDirectory) {
var dirName = item.name;
var url = '<?php echo $this->Html->url(array('controller'=>'nodes', 'action'=>'addchild'));?>';
var data = {'parent_id':parent_id, 'name':dirName, 'type':'Directory'};
$.post(url,data,function(result){
var promises = [];
//adds directory node to tree
$("#treeContainer").jstree('open_node','#'+theNodeId);
$("#treeContainer").jstree('create', '#'+theNodeId, 'last', result,null,true);
parent_id = result["attr"]["data-attr-itemid"];
theNodeId = result["attr"]["id"];
var dirReader = item.createReader();
// Assuming readEntries() is syncrhonous
dirReader.readEntries(function(entries) {
for (var i=0; i<entries.length; i++) {
promises.push(traverseFileTree2(entries[i], parent_id, theNodeId, path + item.name + "/"));
}
});
$.when(promises).then(function(){
// IIRC each argument will be the return value of one of the promises
var files = [];
for(var i = 0; i < arguments.length; i++){
files.concat(arguments[i]);
}
ret.resolve(files);
},function(){
ret.fail();
});
}, 'json');
}
return ret.promise(); // .promise() is "safer" in terms of keeping code isolated
}
请注意,此示例并未过多关注失败案例,其中一个递归目录列表恰好失败。