Javascript文件拖放和读取目录-异步递归

Javascript文件拖放和读取目录-异步递归,javascript,drag-and-drop,html5-filesystem,Javascript,Drag And Drop,Html5 Filesystem,所以我尝试创建一个文件拖放web应用程序。现在,用户可以在屏幕上放置文件,我可以读取这些文件,包括已放置目录中的所有文件。但是,我不知道脚本何时读取完文件 一些代码: 第一个函数处理一个“drop”事件,并将循环遍历每个文件,并将其发送给另一个将读取其内容的函数 function readDrop( evt ) { for( var i = 0; i < evt.dataTransfer.files.length; i++) { var entry = ev

所以我尝试创建一个文件拖放web应用程序。现在,用户可以在屏幕上放置文件,我可以读取这些文件,包括已放置目录中的所有文件。但是,我不知道脚本何时读取完文件

一些代码:

第一个函数处理一个“drop”事件,并将循环遍历每个文件,并将其发送给另一个将读取其内容的函数

function readDrop( evt )
{
    for( var i = 0; i < evt.dataTransfer.files.length; i++)
    {
        var entry = evt.dataTransfer.items[i].webkitGetAsEntry();

        if(entry)
            readContents(entry, "");
    }

    //Do stuff after all files and directories have been read.
}

我不确定该从这里走到哪里,以便在读取所有文件和目录后可以进行回调。

文件系统API似乎不太适合执行完全递归遍历任务,这可能是其他供应商不采用它的部分原因。无论如何,通过一系列神秘的承诺,我认为我能够实现这个目标:

    function traverse_directory(entry) {
        let reader = entry.createReader();
        // Resolved when the entire directory is traversed
        return new Promise((resolve_directory) => {
            var iteration_attempts = [];
            (function read_entries() {
                // According to the FileSystem API spec, readEntries() must be called until
                // it calls the callback with an empty array.  Seriously??
                reader.readEntries((entries) => {
                    if (!entries.length) {
                        // Done iterating this particular directory
                        resolve_directory(Promise.all(iteration_attempts));
                    } else {
                        // Add a list of promises for each directory entry.  If the entry is itself 
                        // a directory, then that promise won't resolve until it is fully traversed.
                        iteration_attempts.push(Promise.all(entries.map((entry) => {
                            if (entry.isFile) {
                                // DO SOMETHING WITH FILES
                                return entry;
                            } else {
                                // DO SOMETHING WITH DIRECTORIES
                                return traverse_directory(entry);
                            }
                        })));
                        // Try calling readEntries() again for the same dir, according to spec
                        read_entries();
                    }
                }, errorHandler );
            })();
        });
    }

    traverse_directory(my_directory_entry).then(()=> {
        // AT THIS POINT THE DIRECTORY SHOULD BE FULLY TRAVERSED.
    });

根据drarmstr的回答,我修改了该函数以符合Airbnb ESLint标准,并希望对其用法和结果作进一步的评论

以下是新功能:

function traverseDirectory(entry) {
  const reader = entry.createReader();
  // Resolved when the entire directory is traversed
  return new Promise((resolve, reject) => {
    const iterationAttempts = [];
    function readEntries() {
      // According to the FileSystem API spec, readEntries() must be called until
      // it calls the callback with an empty array.  Seriously??
      reader.readEntries((entries) => {
        if (!entries.length) {
          // Done iterating this particular directory
          resolve(Promise.all(iterationAttempts));
        } else {
          // Add a list of promises for each directory entry.  If the entry is itself
          // a directory, then that promise won't resolve until it is fully traversed.
          iterationAttempts.push(Promise.all(entries.map((ientry) => {
            if (ientry.isFile) {
              // DO SOMETHING WITH FILES
              return ientry;
            }
            // DO SOMETHING WITH DIRECTORIES
            return traverseDirectory(ientry);
          })));
          // Try calling readEntries() again for the same dir, according to spec
          readEntries();
        }
      }, error => reject(error));
    }
    readEntries();
  });
}
下面是一个drop事件处理程序:

function dropHandler(evt) {
  evt.preventDefault();
  const data = evt.dataTransfer.items;
  for (let i = 0; i < data.length; i += 1) {
    const item = data[i];
    const entry = item.webkitGetAsEntry();
    traverseDirectory(entry).then(result => console.log(result));
  }
}
函数dropHandler(evt){
evt.preventDefault();
const data=evt.dataTransfer.items;
对于(设i=0;iconsole.log(result));
}
}
末尾的
result
变量包含一个数组,反映了拖放文件夹的树结构

例如,下面是我自己网站的git repo,通过上面的代码运行:


这是供比较的Git repo

有趣的一点是您在注释处遗漏的代码//阅读文件-向我们展示该代码,我们可能会帮助您好吧,我想我不认为代码的这一部分有那么重要,但我补充了一点您是现代英雄
function traverseDirectory(entry) {
  const reader = entry.createReader();
  // Resolved when the entire directory is traversed
  return new Promise((resolve, reject) => {
    const iterationAttempts = [];
    function readEntries() {
      // According to the FileSystem API spec, readEntries() must be called until
      // it calls the callback with an empty array.  Seriously??
      reader.readEntries((entries) => {
        if (!entries.length) {
          // Done iterating this particular directory
          resolve(Promise.all(iterationAttempts));
        } else {
          // Add a list of promises for each directory entry.  If the entry is itself
          // a directory, then that promise won't resolve until it is fully traversed.
          iterationAttempts.push(Promise.all(entries.map((ientry) => {
            if (ientry.isFile) {
              // DO SOMETHING WITH FILES
              return ientry;
            }
            // DO SOMETHING WITH DIRECTORIES
            return traverseDirectory(ientry);
          })));
          // Try calling readEntries() again for the same dir, according to spec
          readEntries();
        }
      }, error => reject(error));
    }
    readEntries();
  });
}
function dropHandler(evt) {
  evt.preventDefault();
  const data = evt.dataTransfer.items;
  for (let i = 0; i < data.length; i += 1) {
    const item = data[i];
    const entry = item.webkitGetAsEntry();
    traverseDirectory(entry).then(result => console.log(result));
  }
}