Синхронизируйте forEach с событием внутри (Firebase & node 6.11.5) - PullRequest
0 голосов
/ 10 января 2019

Я читаю, бит за битом, все файлы PNG в каталоге, и мне нужно обобщить некоторые данные в формате json. Проблема состоит в том, что, если я понимаю, программа чтения PNG отправляет асинхронное событие, "проанализированное", когда закончено. Это потому, что функция выходит из-за заселения json ...

Я использую узел 6.11.5, поэтому я не могу использовать sync / await.

var fs = require('fs'),
PNG = require('pngjs').PNG;

exports.movie = functions.https.onRequest((req, res) => {
    console.log('********** START FUNCTION ************');

    var movieFolder = 1;
    if (req.query.id) movieFolder = '../movies/' + req.query.id + '/png/';

    var exitJson = [];

    fs.readdir(movieFolder, (err, files) => {
        files.forEach((file) => {
          fs.createReadStream(movieFolder + file)
            .pipe(new PNG({
                filterType: 1
             }))
            .on('parsed', function () {
                console.log('Parsing: ' + movieFolder + file);
                exitJson.push({
                    width: this.width,
                    height: this.height,
                    data: []
                });
            });
        });
    });
    console.log('************* FINISHED *************');
    res.status(200).json(exitJson);
});

Ответы [ 3 ]

0 голосов
/ 10 января 2019

const exports={};const sizes={'foo.png':[100,200],'bar.png':[200,200],'baz.png':[300,200]};Promise.delay = (t) => new Promise(r => setTimeout(r, t)); const randomTime = (a = 500, b = 1500) => Math.floor(Math.random() * b) + a;
const require=src=>({'fs':{readdir:(d,c)=>{Promise.delay(randomTime()).then(() => c(null,['foo.png','bar.png','baz.png']))},createReadStream:(path)=>({pipe:(f)=>({on:(e,c)=>{const s=sizes[path.split('/').slice(-1)[0]];const a={width:s[0],height:s[1]};a.c=c;Promise.delay(randomTime()).then(() => a.c())}})})},'pngjs':{PNG:class PNG{constructor(a){}}},'firebase-functions':{https:{onRequest:(handler)=>{handler({query:({id:2})},{status:(s)=>({json:(a) => document.getElementById('res').innerHTML = `<pre><code>${JSON.stringify(a, null, 4)}
`})})}}}}) [SRC]; // ------------------- игнорируй вышесказанное const fs = require ('fs'); const PNG = требуется ('pngjs'). PNG; const functions = require ('firebase-functions'); / ** * Используя новое обещание, мы можем выполнить несколько асинхронных задач * в рамках одного Обещания, которое может быть решено или отклонено. Мы читаем * каталог для своих файлов и передайте его нашим обещанным «readFiles». * / функция readMovieFiles (папка) {console.log ('readMovieFiles', папка) вернуть новое обещание ((res, rej) => { fs.readdir (папка, (err, файлы) => { readFiles (файлы, папка) .then (res) .catch (rej) }); }); } / ** * Учитывая массив имен файлов в папке, мы можем связать вместе * файл обещаний с использованием метода Reduce. Начиная с начального значения * Обещание <[]>, каждый файл в массиве будет читаться последовательно. * / функция readFiles (файлы, папка) {console.log ('readFiles', папка, файлы) return Promise.all (files.map (name => readFile (папка + имя))); } / ** * Мы читаем файл и в разобранном обратном вызове вызываем res () и передаем его * вновь созданный массив, содержащий новейший файл для анализа. * / function readFile (path) {console.log ('readFile', path) вернуть новое обещание ((res, rej) => { fs.createReadStream (путь) .pipe (новый PNG ({filterType: 1})) .on ('parsed', function () { console.log ('parsedFile', путь) разреш ({ данные: [], ширина: эта ширина высота: эта высота }); }); }); } exports.movie = functions.https.onRequest ((req, res) => { console.log ('********** ФУНКЦИЯ СТАРТА ************'); if (! req.query.id) req.query.id = 1; readMovieFiles (`../ movies / $ {req.query.id} / png /`) .then (exitJson => { res.status (200) .json (exitJson); }). catch (error => { res.status (500) .json (ошибка); }); console.log ('************* FINISHED *************'); });
<pre><code id="res">
0 голосов
/ 10 января 2019

Вы можете загружать файлы один за другим через рекурсивные вызовы. Не забудьте проверить ошибки.

exports.movie = functions.https.onRequest((req, res) => {
    var movieFolder = 1;
    if (req.query.id) 
        movieFolder = '../movies/' + req.query.id + '/png/';

    var exitJson = [];
    fs.readdir(movieFolder, function (err, files) {
        var sendError = (err) => res.status(500).send(err.message);

        if (err)
            return sendError(err);

        function loadFile (i) {
            if (i == files.length) 
                return res.status(200).json(exitJson); // !!!DONE!!!

            var file = files[i];
            fs.createReadStream(movieFolder + file)
                .pipe(new PNG({filterType: 1}))
                .on('parsed', function () {
                    console.log('Parsing: ' + movieFolder + file);
                    exitJson.push({width: this.width, height: this.height, data: []});
                    loadFile (i + 1); // go to next file
                })
                .on('error', sendError);
        }

        loadFile(0); // start recursion
    }); 
});
0 голосов
/ 10 января 2019

Вы можете использовать простой счетчик itemsProcessed, чтобы определить, были ли разрешены все ваши обратные вызовы.

var movieFolder = 1;
if (req.query.id) movieFolder = '../movies/' + req.query.id + '/png/';

var exitJson = [];

var itemsProcessed = 0;

fs.readdir(movieFolder, (err, files) => {
    files.forEach((file) => {
      fs.createReadStream(movieFolder + file)
        .pipe(new PNG({
            filterType: 1
         }))
        .on('parsed', function () {
            console.log('Parsing: ' + movieFolder + file);
            exitJson.push({
                width: this.width,
                height: this.height,
                data: []
            });
            itemsProcessed++;
            if (itemsProcessed === files.length) {
              console.log('************* FINISHED *************');
              res.status(200).json(exitJson);
            }
        });
    });
});

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...