javascript - 仅在完成异步递归函数后延迟函数执行。

标签 javascript recursion promise

我创建了一个带有拖放功能的文件上传表单,它会递归地遍历放置的文件夹并上传文件和文件夹,并将它们添加到 JSTree 实例中。

这是删除回调

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 完成之前运行。如果可以使用 Promise 来完成,我宁愿不使用回调。

最佳答案

这绝对是一种可以用 Promise 来解决的问题。

  1. 设计traverseFileTree2(),使其始终返回 promise /延迟,即使您实际上没有启动任何异步内容。
    • 该 Promise 的成功处理程序应提供它找到的文件列表。
    • 如果您发起一堆递归调用,请列出它们的 promise 列表,并使用 $.when() 等待它们全部完成,然后再对它们进行操作.
  2. 类似地,在主循环中,收集顶级 Promise 列表(来自 traverseFileTree2()),并再次使用 $.when() 将它们组合起来 promise 当所有这些都结束时“完成”,汇总他们的文件列表。 (没有共享 filesToQueue 变量,都是返回值。)
  3. 设置 addFilesToUploadQueue() 在这个巨大的最后一个 promise 成功时调用,获取 promise 的文件到队列的返回数据

这是一个未经测试的重写,但即使它有缺陷,希望足以让人们理解这个想法:

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
}

请注意,此示例并没有过多关注失败情况,其中一个递归目录列表恰好失败。

关于javascript - 仅在完成异步递归函数后延迟函数执行。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20129330/

相关文章:

javascript - 递归添加点击事件处理程序

javascript - 即时为 Promise.all() 构建一系列 Promise

javascript - 仅在主页上隐藏 CSS 类

javascript - jQuery 倒计时在暂停时运行

javascript - 理解Android webview javascript接口(interface)

javascript - 使用 setTimeout 避免堆栈溢出

java - 堆栈是从 0 开始还是从 1 开始?

javascript - Q.all 用于非 promise 和 promise 组合

javascript - Bluebird Promise.all 没有被调用

javascript - 如何将 CustomMarker 与 MarkerClustererPlus 结合使用?