Объедините результат обещаний в один массив в JavaScript

Я пытаюсь разобрать все файлы, которые были загружены в виде каталога, в единый массив файлов. У меня проблема в том, что я не могу объединить результат всех обещаний в один массив. Вместо этого я получаю многомерный массив.

function iterateThroughUploadedFiles(files, isEntry = false) {
    var promises = [];
    for (let i = 0; i < files.length; i++) {
        let entry = isEntry ? files[i].webkitGetAsEntry() : files[i];
        if (entry.isFile) {
            promises.push(new Promise(function(resolve, reject) {
                getFile(entry, resolve, reject);
            }));
        }
        else if (entry.isDirectory) {
            let dirReader = entry.createReader();

            var promise = new Promise(function(resolve, reject) {
                readEntries(dirReader, resolve, reject);
            });

            promises = promises.concat(promise);
        }
    }
    return Promise.all(promises);
}

function getFile(fileEntry, resolve, reject) {
    fileEntry.file(function(file) {
        resolve(file)
    });
}

function readEntries(dirReader, resolve, reject) {
    dirReader.readEntries(function (entries) {
        resolve(iterateThroughEntries(entries).then(function(result) {
            return result;
        }));
    });
}

Применение:

iterateThroughUploadedFiles(files, true).then(function(result) {
    console.info(result);
});

Когда я выполняю функцию iterateThroughUploadedFiles, переменная result представляет собой многомерный массив. Однако я хочу, чтобы этот массив был сглаженным (пример: [Файл (6148), Массив (1), Массив (0), Файл (14)]). Я не очень знаком с обратными вызовами и обещаниями ... поэтому у меня есть некоторые проблемы при работе с ними.

Редактировать:
Я допустил опечатку внутри функции readEntries(dirReader, resolve, reject). Вместо функции iterateThroughUploadedFiles должна быть функция iterateThroughEntries.

readEntries и getFile должны возвращаться обещать, что они конструируют сами, а не принимают resolve / reject в качестве обратных вызовов.
Bergi 01.07.2018 15:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
1 427
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
return Promise.all(promises);

Это преобразуется в двумерный массив, который вы можете легко сгладить, используя некоторые функции генератора:

function* flatten(arr) {
  for(const el of arr) {
    if (Array.isArray(el)) {
      yield* flatten(el);
    } else {
      yield el;
    }
  }
}

return Promise.all(promises).then(array => ([...flatten(array)]));

Хотя передача resolve и reject работает вроде как, это можно сделать более элегантно, просто вернув новое обещание из функции getFile:

function getFile(fileEntry, resolve, reject) {
   return new Promise(resolve => fileEntry.file(resolve));
}

Тогда его можно легко приковать

function readEntries(dirReader) {
  return new Promise(resolve => dirReader.readEntries(resolve))
    .then(iterateThroughEntries);
}

function iterateThroughUploadedFiles(files, isEntry = false) {
   return Promise.all( files.map( file => {
     let entry = isEntry ? file.webkitGetAsEntry() : file;
     if (entry.isFile) {
       return getFile(entry);
     } else if (entry.isDirectory) {
       return readEntries( entry.createReader());
     }
   })).then(array => ([...flatten(array)]));
}

Я бы подумал, что array => [].concat(...array) поможет сгладить двумерный массив - или даже [].concat.apply([], array), если рассматриваемый JS-движок поддерживает стрелочные функции, но не оператор распространения.

Jaromanda X 01.07.2018 10:41

Это решает только двумерную проблему, но возможно ли, что у меня есть более размерные массивы.

David_Zizu 01.07.2018 10:50

@david, да, посмотрите отредактированную версию;)

Jonas Wilms 01.07.2018 10:57

Другие вопросы по теме