Чтобы понять, что может пойти не так, напечатайте console.log в конце метода.
Что вообще может пойти не так:
- Произвольный заказ.
- printFiles может завершить работу перед печатью файлов.
- Низкая производительность.
Они не всегда ошибочны, но часто встречаются в стандартных случаях использования.
Как правило, использование forEach приводит ко всем, кроме последнего. Он будет вызывать каждую функцию, не дожидаясь завершения функции, что означает, что он сообщает всем функциям о запуске, а затем завершает работу, не дожидаясь завершения функций.
import fs from 'fs-promise'
async function printFiles () {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))
for(const file of files)
console.log(await file)
}
printFiles()
Это пример нативного JS, который сохранит порядок, предотвратит преждевременный возврат функции и теоретически сохранит оптимальную производительность.
Это будет:
- Инициировать параллельное чтение всех файлов.
- Сохранение порядка с помощью сопоставления имен файлов с ожидаемыми обещаниями.
- Ждать каждого промиса в порядке, определенном массивом.
С этим решением первый файл будет показан, как только он будет доступен, без необходимости ждать, пока другие станут доступны первыми.
Он также будет загружать все файлы одновременно, а не ждать, пока завершится первый, прежде чем можно будет начать чтение второго файла.
Единственным недостатком этой и исходной версии является то, что если одновременно запустить несколько операций чтения, то будет сложнее обрабатывать ошибки из-за большого количества ошибок, которые могут произойти одновременно.
В версиях, которые считывают файл за раз, затем останавливаются при сбое, не тратя время на попытки прочитать другие файлы. Даже при наличии тщательно продуманной системы отмены может быть сложно избежать сбоя при первом файле, но уже при чтении большинства других файлов.
Производительность не всегда предсказуема. Хотя многие системы будут работать быстрее при параллельном чтении файлов, некоторые предпочтут последовательное. Некоторые из них являются динамическими и могут переключаться под нагрузкой, а оптимизации, обеспечивающие задержку, не всегда обеспечивают хорошую пропускную способность при высокой конкуренции.
В этом примере также нет обработки ошибок. Если что-то требует, чтобы они либо все были успешно показаны, либо не отображались вовсе, этого не произойдет.
Рекомендуются тщательные эксперименты с console.log на каждом этапе и поддельные решения для чтения файлов (вместо случайной задержки). Хотя многие решения, по-видимому, делают то же самое в простых случаях, все они имеют небольшие различия, которые требуют дополнительной проверки, чтобы их выявить.
Используйте этот макет, чтобы показать разницу между решениями:
(async () => {
const start = +new Date();
const mock = () => {
return {
fs: {readFile: file => new Promise((resolve, reject) => {
// Instead of this just make three files and try each timing arrangement.
// IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
const time = Math.round(100 + Math.random() * 4900);
console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
setTimeout(() => {
// Bonus material here if random reject instead.
console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
resolve(file);
}, time);
})},
console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
};
};
const printFiles = (({fs, console, getFilePaths}) => {
return async function() {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));
for(const file of files)
console.log(await file);
};
})(mock());
console.log(`Running at ${new Date() - start}`);
await printFiles();
console.log(`Finished running at ${new Date() - start}`);
})();
почему вы вызываете
printFiles
функцию более высокого порядка, если она не получает функцию в качестве аргумента или не возвращает функцию в качестве вывода?@KernelMode Метод
forEach
здесь является функцией высшего порядка.