Щоб побачити, як це може піти не так, надрукуйте console.log в кінці методу.
Те, що в цілому може піти не так:
- Довільний порядок.
- Файли друку можуть закінчити роботу перед друком файлів.
- Погана продуктивність.
Вони не завжди помиляються, але часто трапляються у звичайних випадках використання.
Як правило, використання 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 ...
працює?