[JavaScript] Chrome App MediaGalleries und Promises

Parantatatam

mag Cookies & Kekse
Hallo Tutorianer,

ich bin gerade dabei eine eigene Chrome-App zu erstellen, in welcher es unter anderem notwendig ist, dass man MediaGalleries rekursiv durchsuchen kann, um alle Dateien und Verzeichnisse daran am Ende in einem Array zu haben. Da das Auslesen der APIs von Chrome-Apps über Callbacks läuft, ist das ein wenig schwieriger, weshalb ich das gerne über die Promise-API lösen wollte. Jedoch komm ich gerade nicht dahinter, wie ich es so lösen kann, dass mir eine Funktion am Ende ein Promise-Objekt zurückliefert, welches mir dann einen Callback ermöglicht, welcher mir alle gefundenen Einträge liefert.
Javascript:
var files = [];

function readEntries (entries) {
  for ( var i in entries ) {
    files.push( entries[i] );
    if ( entries[i].isDirectory ) {
      entries[i].root.createReader().readEntries( readEntries );
    }
  }
}
Allerdings ist hiermit nicht sichergestellt, dass direkt nach dem Aufruf der Funktion alle Einträge gefunden wurden. Außerdem möchte ich keine "globale" Variable haben, in der ich die Einträge sammle.

Mein Problem besteht hauptsächlich darin, wann ich den Resolve-Aufruf des Promise-Objektes starten soll, da ich durch die Callbacks doch nie genau weiß, ob ein Callback nun der letzte ist oder nicht. Vielleicht befinde ich mich damit aber auch nur in einer Sackgasse und es gibt eine Möglichkeit, mit der ich genau das umgehen oder lösen kann.
 
Zuletzt bearbeitet:
Nach einigem Kopfzerbrechen und ausprobieren, bin ich jetzt selber auf eine Lösung gekommen, die wirklich elegant ist. Dabei haben mir unter anderem folgende Beiträge geholfen:
Meine Lösung sieht nun wie folgt aus, falls sie jemand mal braucht:
Javascript:
// Hilfsfunktion um multidimensionale Arrays auf eine Ebene zu bringen
var flatten = function (items) {
  var res = [];
 
  for ( var i in items ) {
    if ( items[i] instanceof Array ) {
      res = res.concat( flatten( items[i] ) );
    } else {
      res.push( items[i] );
    }
  }
 
  return res;
};

MediaGalleries.readEntries = function (entry, options) {
  options = options || {};
   
  if ( options.recursive === "yes" ) {
    // return the final promise that is accessable from the outside
    return new Promise(function (resolve) {
      // define the recursive reader function
      var recursive = function (entry) {
        // read all child entries of the current entry
        return MediaGalleries.readEntries(entry).then(function (entries) {
          // collect all promises
          var promises = [];
         
          // walk through all entries of this directory
          for ( var i in entries ) {
            // add entry to list of promises
            promises.push( entries[i] );
           
            // recursive read child entries of current entry
            // if it is a directory (directories often have entries ;) )
            if (entries[i].isDirectory) {
              promises.push( recursive( entries[i] ) );
            }
          }
         
          // wait for all promises to be resolved
          return Promise.all( promises );
        });
      };
     
      // start recursive progress
      recursive(entry).then(function (entries) {
        // get all collected entries and flatten them to a one dimensional array
        resolve( flatten( entries ) );
      });
    });
  } else {
    return new Promise(function (resolve, reject) {
      entry = (entry.root ? entry.root : entry);
     
      if ( !entry.isDirectory ) {
        reject( new Error("no directory") );
        return;
      }
     
      if ( !entry.createReader || typeof( entry.createReader ) !== "function" ) {
        reject( new Error("cannot create reader for current directory") );
        return;
      }
     
      var reader = entry.createReader();
     
      if ( !reader.readEntries || typeof( reader.readEntries ) !== "function" ) {
        reject( new Error("cannot read entries of current directory") );
        return;
      }
     
      // read entries of current directory and sort them by their full relative path
      reader.readEntries(function (entries) {
        entries.sort(function (a, b) {
          return a.fullPath.localeCompare( b.fullPath );
        });
        resolve( entries );
      });
    });
  }
};
Wenn man dann einen Verzeichniseintrag hat, kann man das Ganze so anwenden:
Javascript:
MediaGalleries.readEntries(entry, { "recursive": "yes" }).then(function (entries) {
  console.log( entries ); // array of entries
});
 

Neue Beiträge

Zurück