Para ver como isso pode dar errado, imprima console.log no final do método.
Coisas que podem dar errado em geral:
- Ordem arbitrária.
- O printFiles pode terminar a execução antes da impressão dos arquivos.
- Mau desempenho.
Eles nem sempre estão errados, mas frequentemente estão em casos de uso padrão.
Geralmente, o uso de forEach resultará em todos, exceto no último. Ele chamará cada função sem aguardar a função, o que significa que diz para todas as funções iniciarem e termina sem aguardar o término das funções.
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()
Este é um exemplo em JS nativo que preservará a ordem, impedirá o retorno prematuro da função e, em teoria, manterá o desempenho ideal.
Isso vai:
- Iniciar todas as leituras do arquivo para acontecer em paralelo.
- Preserve a ordem usando o mapa para mapear nomes de arquivos com as promessas a aguardar.
- Aguarde cada promessa na ordem definida pela matriz.
Com esta solução, o primeiro arquivo será mostrado assim que estiver disponível, sem precisar esperar que os outros estejam disponíveis primeiro.
Ele também carregará todos os arquivos ao mesmo tempo, em vez de esperar que o primeiro termine antes que a segunda leitura do arquivo possa ser iniciada.
O único inconveniente disso e da versão original é que, se várias leituras forem iniciadas ao mesmo tempo, é mais difícil lidar com erros, pois há mais erros que podem acontecer ao mesmo tempo.
Nas versões que lêem um arquivo de cada vez, ele pára em uma falha sem perder tempo tentando ler mais arquivos. Mesmo com um sistema de cancelamento elaborado, pode ser difícil evitar falhas no primeiro arquivo, mas a leitura da maioria dos outros arquivos também.
O desempenho nem sempre é previsível. Enquanto muitos sistemas serão mais rápidos com leituras paralelas de arquivos, alguns preferirão sequenciais. Alguns são dinâmicos e podem mudar sob carga, otimizações que oferecem latência nem sempre produzem um bom rendimento sob contenção pesada.
Também não há tratamento de erros nesse exemplo. Se algo exige que todos sejam mostrados com sucesso ou não, isso não será possível.
Recomenda-se a experimentação aprofundada com o console.log em cada estágio e soluções falsas de leitura de arquivos (em vez de atraso aleatório). Embora muitas soluções pareçam fazer o mesmo em casos simples, todas têm diferenças sutis que exigem um exame minucioso extra.
Use esse mock para ajudar a diferenciar as soluções:
(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 ...
funciona?