Чтобы увидеть, как это может пойти не так, напечатайте 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}`);
})();
for ... of ...
работает?