Hallo Steffen,
JavaScript macht alles asynchron, was länger als ein Augenklimpern dauert. Der Grund ist, dass es zusammen mit der Layout-Engine des Browsers in einer Ausführungskette hängt und diese keine Parallelverarbeitung vorsieht.
Es gibt im Browser mehrere Ereignisquellen. Timer, Bildschirmanzeige, Maus, Tastatur, und auch Vorgänge, die im Hintergrund ablaufen und fertig werden.
Jede Quelle kann ein Ereignis auslösen, und wenn auf dieses Ereignis ein JavaScript-Handler registriert ist, wird er ausgeführt. Nach dieser Ausführung wird die Anzeige neu layoutet.
Das muss alles fix gehen, denn solange ein Eventhandler läuft, kann kein anderer laufen. Um Dir und mir die Hölle der Multithreading-Programmierung fernzuhalten. Und deswegen werden Vorgänge, die auf externe Ressourcen zugreifen müssen, geteilt. Du stößt sie in deinem Script an, der Browser führt sie im Hintergrund aus und wenn sie fertig sind, melden sie sich zurück. DAS ist dann aber ein neues Event.
Bau mal in deine Funktionen console.log Aufrufe ein, die Dir ausgeben, wann iterateFilesAndDirs beginnt und endet, und wann deine beiden Callbacks beginnen und enden.
Man sieht es gelegentlich auch auf dem Bildschirm. Der Inhalt eines Unterverzeichnisses wird von meinem Fiddle nachträglich ins DOM eingebaut. Deswegen kann es zu einem kurzen Flackern kommen, wenn sich ein Teil der Anzeige auf einmal nach unten verschiebt. Bei Dir mag das anders sein, weil Du nur Dateien einsammelst, aber auch hier musst Du aufpassen.
Denn sowohl dein .push(file) Aufruf wie auch die rekursiven Aufrufe von iterateFilesAndDirs sind asynchron, d.h. sie sind längst nicht fertig, wenn dein drop-Eventhandler fertig ist. Wenn Du aus dem drop-Eventhandler die iterateFilesAndDirs Funktion aufrufst und sie zurückkehrt, steht in allFiles vermutlich noch gar nichts drin. Das füllt sich erst nach einiger Zeit.
Woher weißt Du, dass Du weitermachen kannst?
Zunächst solltest Du in einer Variable neben allFiles zählen, wieviele Files Du gefunden hast. Diesen Zähler erhöhst Du im isFile Teil vor dem item.file() Aufruf.
Sodann schreibst Du eine Funktion uploadFile. Die rufst Du nicht sofort auf, sondern mit einer kurzen Verzögerung. Wenn Dir nämlich jemand einen Ordner droppt, der NUR Unterverzeichnisse enthält, dann ist nach dem ersten iterateFilesAndDirs Aufruf das allFiles Array noch leer. Bis sich das füllt, müssen die DirectoryReader für die Unterverzeichnisse durch sein und etwas gefunden haben. 50ms Wartezeit merkt keiner, und Du liest ja nicht von einem Diskettenlaufwerk, also:
function handleDropEvent(event) {
iterateFilesAndDirs(event.dataTransfer.items, "/");
setTimeout(uploadFiles, 50);
}
function uploadFiles() {
if (allFileCount == 0) // Nichts mehr zu tun
return;
if (allFiles.length == 0) // Noch nicht lange genug gewartet
setTimeout(uploadFiles, 50);
let file = allFiles.shift();
// Upload anstoßen, wenn er fertig ist, uploadFiles() neu aufrufen
}
Zumindest würde ich das auf diese Weise steuern.
Rolf
sumpsi - posui - obstruxi