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



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


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-движок поддерживает стрелочные функции, но не оператор распространения.
Это решает только двумерную проблему, но возможно ли, что у меня есть более размерные массивы.
@david, да, посмотрите отредактированную версию;)
readEntriesиgetFileдолжны возвращаться обещать, что они конструируют сами, а не принимаютresolve/rejectв качестве обратных вызовов.