Javascript file dropping and reading directories - Asynchronous Recursion

戏子无情 提交于 2019-12-04 15:09:10

The FileSystem API doesn't seem well suited for the task of a full recursive traversal, perhaps that's part of the reason why other vendors are not adopting it. Anyway, with an arcane combination of Promises I think I was able to accomplish this goal:

    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.
    });

Following on from the answer by drarmstr, I modified the function to be compliant with the Airbnb ESLint standards, and wanted to make some further comments on its usage and results

Here's the new function:

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();
  });
}

here's a drop event handler:

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));
  }
}

The result variable at the end contains an array, mirroring the tree structure of the folder you dragged and dropped.

For example, here is a git repo for my own site, ran through the above code:

Here's the Git repo for comparison https://github.com/tomjn/tomjn.com

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!