как асинхронно считывать и суммировать данные всех файлов с помощью async / await

#node.js #async-await

#node.js #async-await

Вопрос:

Я знаю, что bluebird или fs-promise или даже es6 promise могут это сделать. Как показано ниже, я сделал.

Но я хочу использовать последнюю версию es7 async / await для достижения. Я просто не понимаю, как использовать async / await в цикле for (а затем суммировать их результаты).

Большинство примеров, которые я искал в Google, касаются выборки / ajax.get. Но я хочу читать файлы и суммировать данные вместе.

Может у кого-нибудь есть подсказка? Спасибо.

 var fs = require("fs");
var Promise = require("promise");


function readDir(){
    var p = new Promise( function(resolve, reject) {
        fs.readdir( ".", function( err, files) { 
            resolve(files);
        })
    } );
    return p;
}



function readFile(file){
    var p = new Promise( function(resolve, reject) {
        fs.readFile( file, function( err, data) { 
            console.log("Successfully read a file.", file);
            resolve(data);
        })
    } );
    return p;
}



readDir().then(function(files){
    var promises = [];
    for ( var i = 0; i < files.length; i   ) {
        promises.push( readFile(files[i]) );
    }

    Promise.all( promises ).then( function(results) {
        var totalBytes = 0;
        for ( i = 0; i < results.length; i   ) {
            totalBytes  = results[i].length;
        }
        console.log("Done reading files. totalBytes = "   totalBytes);
    });
});
  

Ответ №1:

Прежде всего, чтобы использовать async / await, нам все равно понадобятся обещания. Просто потому, что в отличие от promises мы не можем await вызывать функции на основе обратного вызова.

Итак, чтобы начать, я предлагаю использовать .promisifyAll метод bluebird, чтобы все fs методы, за которыми следует постфикс ‘Async’, возвращали обещания.

Как минимум, у вас будет:

 'use strict';

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

async function readFile(file) {
    let data = await fs.readFileAsync(file);
    console.log('Successfully read a file.', file);

    return data;
}

async function getTotalBytes() {
    let files = await fs.readdirAsync('.');

    //Making a promise for each file to read it.
    let promises = files.map(f => readFile(f));
    //Reading all in parallel
    let results = await Promise.all(promises);

    //Using native .reduce to sum the bytes
    let totalBytes = results.reduce((memo, r) => {
        return memo   r.length;
    }, 0);

    console.log('Done reading files. totalBytes = '   totalBytes);
    return totalBytes;
}

//Running out function
getTotalBytes()
    .then(bytes => console.log(bytes))
    .catch(err => console.error(err));  

Существует проблема с этим кодом. При попытке доступа к каталогу будет выдана ошибка .readFile . Таким образом, мы могли бы отфильтровать каталоги следующим образом:

 async function getTotalBytes() {
    let files = await fs.readdirAsync('.');
    let promises = [];
    for (let file of files) {
        let stat = await fs.statAsync(file);
        if (!stat.isDirectory()) {
            promises.push(readFile(file));
        }
    }

    let results = await Promise.all(promises);
    let totalBytes = results.reduce((memo, r) => {
        return memo   r.length;
    }, 0);

    console.log('Done reading files. totalBytes = '   totalBytes);
    return totalBytes;
}  

Комментарии:

1. вы можете использовать util.promisify вместо добавления пакета. Подробнее здесь zeit.co/blog/node-8