2013-11-21 100 views
2

我使用拖放功能創建了一個文件上傳表單,它在遞歸的文件夾上遞歸地迭代並上傳文件和文件夾,並將它們添加到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'); 
} 

}

我在這裏的問題是,功能完成traverseFileTree2之前addFilesToUploadQueue(filesToQueue)運行遞歸異步功能。我不想使用回調,如果這可以使用承諾來完成。

回答

2

這絕對是你可以用承諾攻擊的問題。

  1. 設計traverseFileTree2()使其總是返回一個承諾/推遲,即使你實際上並沒有推出任何異步的。
    • 該承諾的成功處理程序應提供它找到的文件列表。
    • 如果您啓動一堆遞歸調用,請列出承諾,並使用$.when()等到它們全部完成後再執行某些操作。
  2. 同樣,在你的主循環,收集頂級承諾的列表(從traverseFileTree2()),並再次使用$.when()將它們組合成的「完成」時,所有的人都過來,聚集承諾其文件列表。 (沒有共享filesToQueue變量,它的所有的返回值。)
  3. 設置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 
} 

請注意,這個例子並沒有太注意失敗情況,其中遞歸目錄列表之一發生失敗。

+0

.file()是異步的 – josephtikva1

+1

我最終重寫了這個。看到這個https://gist.github.com/josephtikva/7696280 – josephtikva1

相關問題