简体   繁体   English

在vanilla js中检测文件夹放置事件的完成

[英]Detect completion of folder drop event in vanilla js

I am trying to determine if a directory tree has been fully traversed after is was dropped on a page.我试图确定在将目录树放在页面上后是否已完全遍历它。 That is: I would like to know when the next process can start after the full folder and sub-directories has been process by the drop event code.那就是:我想知道在 drop 事件代码处理完完整文件夹和子目录后,下一个进程何时可以开始。

As an example, in the code below I want send the M.files via json to sever.作为一个例子,在下面的代码中,我想通过 json 发送 M.files 来切断。 To do this I need to know when the folder is processed.为此,我需要知道文件夹何时被处理。 The Ajax call is not shown.未显示 Ajax 调用。

The recursive directory tree traversal function:递归目录树遍历函数:

async function processEnt(ent,n,fls){
    n = n==undefined? 0:n;
    
 
    if( ent.isFile ){
        fls.files.push(ent.name)        
    }    
    else if (ent.isDirectory){
        
        fls.dirs[ent.name]={ "files":[], "dirs":{},"done":false }                
        var r = ent.createReader()        
        
        await r.readEntries(
            async function f(ents){                                                
                if(ents.length >0){                    
                    for(var e of ents){
                       await processEnt(e,n+1,fls.dirs[ent.name])                    
                    }                                 
                    await r.readEntries(f)
                }
                
            }
        )
        
    }    
    console.log(n +" level done")    
        
}


   

The drop event function: drop事件函数:

async function onDrop(evt){
    evt.preventDefault()
    evt.stopPropagation()
    
    M.files = {
        "files":[],
        "dirs":{}
    }    
    for(item of evt.dataTransfer.items){                
        await processEnt( item.webkitGetAsEntry(),0,M.files )    
    }
    
    console.log("on drop done")
    
}

I come up with a possible answer.我想出了一个可能的答案。

M.paths hold the number of active paths and is incremented for each sub-directory past the first. M.paths保存活动路径的数量,并且对于第一个之后的每个子目录都会增加。 The handling of files and directories has also been slightly changed.文件和目录的处理也略有变化。 A timer is used to pole the M.paths to see if all of the paths have been completed.计时器用于对M.paths进行M.paths以查看是否所有路径都已完成。

There may exists a race condition in that the first sub-directory is processed and M.paths is decremented before any the other directories on that level is processed.可能存在竞争条件,因为第一个子目录被处理并且M.paths在该级别上的任何其他目录被处理之前递减。

The drop event:掉落事件:

function onDrop(evt){
    evt.preventDefault()
    evt.stopPropagation()
            
   
    M.paths = 0 
    M.files = {
        "files":[],
        "dirs":[]
    }    
    
    for(item of evt.dataTransfer.items){                
        ent = item.webkitGetAsEntry()
        if(ent.isFile){
           M.files["files"].push(ent) 
        }else if(ent.isDirectory) {
            M.paths+=1
            processDirectory(ent,0,M.files )                
        }
    }
    
    window.setTimeout(function f(){
            if(M.paths==0){
                // drop envent processed 
                //run update or send info to server
                console.log("Drop event done")                    
                
            }else{
                window.setTimeout(f,500)
            }
        },500)
} 

Function to process each directory:处理每个目录的函数:

function processDirectory(ent,n,fls){
    n = n==undefined? 0:n;
        
    var new_dir ={"ent":ent,"files":[],"dirs":[]}
    fls["dirs"].push(new_dir)
    var r = ent.createReader()        
    r.readEntries(
        function f(ents){                                                                
            var leaf = true
            var add_path =0
            for(let entc of ents){
                if ( entc.isDirectory ){
                    M.paths+= add_path
                    add_path = 1
                    console.log(n+":"+M.paths+":"+entc.name)
                    leaf = false
                    processDirectory(entc,n+1,new_dir)
                    
                }else if( entc.isFile){
                    new_dir["files"].push(ent)
                }     
            }
            if(leaf){ M.paths--}                
        }            
    )   
}

This seems to work though I have not tested it thoroughly.这似乎有效,尽管我还没有对其进行彻底的测试。 Also if there are many entries it will not get all of them.此外,如果有很多条目,则不会获得所有条目。 See https://stackoverflow.com/a/53058574/2975893 for details.有关详细信息,请参阅https://stackoverflow.com/a/53058574/2975893

I found a solution which seems to do the trick.我找到了一个似乎可以解决问题的解决方案。

The drop event function: drop事件函数:

function onDrop (evt){
    
    evt.preventDefault()
    evt.stopPropagation()
    
    var promises = []
    
    for(item of evt.dataTransfer.items){
        //create new Promise that calls processItem function
        // the promise is used to track if the work is complete
        var p  = new Promise( function(res, rej){
        
                processItem(item.webkitGetAsEntry(),res,rej)
            })
            
        // record each promise
        promises.push( p )
        
    }
    
    // the drop event is complete when all of the item (child)
    // promises are completed
    Promise.all( promises ).then(function(){
        // code for after the drop event
    })
    
}

The function that processes each item function processItem (item,res,rej){处理每个item的函数 function processItem(item,res,rej){

    if (ent.isFile){
        //handle file entry
        
        //complete this items promise
        res()
    }
    else if (ent.isDirectory){
    
        var promises = []
        var dirReader = ent.createReader()
        
        
        function read( entries ){
        
            if (entries.length > 0 ){                
            
                for(var e of entries){
                    var p = new Promise( function(resm,rejm) {                    
                        processItem(e,resm,rejm)
                        })
                    promises.push(p)
                }
                /*
                "readEntries" called again to ensure all entries are read as 
                "readEntries" does not read all files when there 
                is a large amount of files
                */
                dirReader.readEntries(read)
            }
        
        }
        else{
            /*
              if there are no more entries ensure all entries 
              in the directory are processed
             */
             Prmoise.all( promises ).then(function(){
                // once all promises are complete complete this items promise
                res()
            })
            
        }
        // start the read process
        dirReader.readEntries(read)
    }        


}

In testing all processes completed before their parents.在测试之前完成所有进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM