Выполнение обещаний в JavaScript - PullRequest
1 голос
/ 16 марта 2020

У меня проблемы с получением обещаний работать так, как мне нужно. Я испробовал много разных способов выполнить обещание, но ничего, что я сделал, не будет работать так, как мне нужно. Я пытаюсь получить перетаскивание файла, работающего на веб-странице. Мне нужен список всех файлов в наборе (this.files), который передается в вызов для загрузки файлов. Проблема в том, что Promise.all запускается до того, как обещания будут выполнены.

Я все еще пытаюсь сосредоточиться на обещаниях, поэтому, возможно, я все неправильно понял, но, судя по результатам всех моих исследований, это должно сработать , Любая помощь будет оценена.

  async dndDropFiles(event) {
    event.preventDefault();
    let ptable = [];
    this.files = new Set();
    if (event.dataTransfer.types[0] === "Files") {
      var items = event.dataTransfer.items;
      for (var i=0; i<items.length; i++) {
        // webkitGetAsEntry is where the magic happens
        var item = await items[i].webkitGetAsEntry();
        if (item) {
          ptable.push(new Promise(async resolve => {
            resolve(await this.dndTraverseFileTree(item, ""));
          }))
        }
      }  
      Promise.all(ptable)
        .then( (results) => {
          if (this.files.size > 0) {
            this.progress = this.uploadService.upload(this.files, this.currentDir, this.currentProject);
          }    
        })
    }
  }

  async dndTraverseFileTree(item, path) {
    if (item.isFile) {
      // Get file
      item.file((file) => {
        this.files.add(file);
      });
  } else if (item.isDirectory) {
      // Get folder contents
      let ptable = [];
      var dirReader = await item.createReader();
      dirReader.readEntries((entries) => {
        for (var i=0; i<entries.length; i++) {
          ptable.push(new Promise( async resolve => {
            resolve(await this.dndTraverseFileTree(entries[i], path + item.name + "/"));
          }));
        }
        Promise.all(ptable)
          .then (results => {});
      });
    }
  }

1 Ответ

3 голосов
/ 16 марта 2020

Такое ощущение, что вы делаете вещи слишком сложными, и я предлагаю еще одно хорошее прочтение стандартов кодирования и способа работы Promises :) Конструкция async / await была введена для повышения читабельности кода.

В любом случае, у меня есть некоторый непроверенный код здесь. Но это должно сработать. Также я настоятельно советую вам добавить набор текста. Вы используете angular, поэтому я могу только предположить, что вы используете TypeScript. При наборе текста вы будете делать меньше ошибок, и компилятор поможет вам в этом.

Прежде чем я приведу код, этот webkitGetAsEntry не является стандартным. Его следует использовать только в том случае, если вы действительно не хотите использовать старые браузеры или safari / ios:

Нестандартные. Эта функция нестандартна и не соответствует стандартам. Не используйте его на рабочих сайтах, выходящих в Интернет: он не будет работать для каждого пользователя. Также могут быть большие несовместимости между реализациями, и поведение может измениться в будущем.

Но вы можете go об этом так. Первая функция для обработки события. Второй пересечь дерево:

async dndDropFiles(event: DragEvent): Promise<void> {
  if (event.dataTransfer.types[0] !== "Files" || !event.dataTransfer.items) {
    return;
  }

  const entries = [...(event.dataTransfer.items as any)].map(
    item => item.webkitGetAsEntry()
  );

  const allEntries = await this.dndTraverseFileTree(entries);

  const files = await Promise.all(
    allEntries.map(
      (entry) => new Promise((resolve, reject) => entry.file(resolve, reject))
    )
  );

  this.files = new Set(files);

  if (this.files.size > 0) {
    this.progress = this.uploadService.upload(
      this.files, this.currentDir, this.currentProject
    );
  }
}

async dndTraverseFileTree(entries: any[]): Promise<any[]> {
  const dirs = entries.filter(entry => !!entry && entry.isDirectory);
  const files = entries.filter(entry => !!entry && entry.isFile);

  if (dirs.length) {
    const childEntries = (
      await Promise.all(
          dirs.map(dir => new Promise(
            (resolve, reject) => dir.createReader().readEntries(resolve, reject))
          )
        )
    ).flat();

    return this.dndTraverseFileTree(childEntries);
  }

  return [ ...files ];
}
...