node.js обещания в цикле for

Я пытаюсь добиться слияния нескольких файлов (и создания PDF-документов, если результат базы данных возвращает несколько элементов с непустым полем «json»).

Теперь слияние происходит только один раз и объединяет первый элемент с element['json'] != '' с самим собой.

Merging logic is:

  • все PDF-файлы уже созданы, за исключением этого, который мы создадим следующим
  • если элемент содержит JSON, создайте PDF
  • если элемент не содержит JSON, объединить его с предыдущим PDF
  • Может быть, помогает помещение всех промисов в массив и передача их в Promise.all()? Действительно застрял сейчас.

    app.get("/api/generatePDF", jsonParser, function(req, res) {
    
    var saveFilename, savePath;
    var idDocument, idPatient, idDoctor, idItem;
    var orientation = "";
    var url = req.route.path;
    var tbl = "";
    var html = "";
    var hasTables = 0;
    console.log(req.query.json);
    var savedJSON = JSON.parse(req.query.json);
    var flag = 4;
    var id_inventory = parseInt(savedJSON['id_inventory']);
    var request = new sql.Request();
    var files = new Array();
    var badFiles = new Array();
    var options = "";
    var mergeNeeded = parseInt(savedJSON['param']);
    if (mergeNeeded == 1) {
        flag = 14;
    }
    var cnt = 0;
    var output = parseInt(savedJSON['output']);
    var mergedName = savedJSON['merged_name'];
    var numRows = 0;
    var idSpec = mergeNeeded;
    if (id_inventory == 0) {
        var pid = savedJSON['id_patient'];
        var idDocType = savedJSON['id_doc_type'];
        idSpec = savedJSON['id_spec'];
        flag = 10;
        request.input('id_patient', sql.Int, pid);
        request.input('id_doc_type', sql.Int, idDocType);
    }
    request.input('id_spec', sql.Int, idSpec);
    request.input('flag', sql.Int, flag);
    request.input('redo', sql.Int, 1);
    request.input('id_inventory', sql.Int, id_inventory);
    
    request.execute("create_json").then(function(result) {
        var size = result.recordset.length;
        return Promise.all(result.recordset.map(function(element) {
    
                savePath = element['path'];
                idItem = element['id_item'];
                saveFilename = element['filename'];
                options = { "format": "A4", "orientation": element['orientation'], "renderDelay": "undefined", "border": "10mm" }
                idPatient = element['id_patient'];
                htmlFile = element['id_template'];
                var fillTemplate = new Promise((resolve, reject) => {
                    files.push(basePath + element['path'] + separator + element['filename']);
                    if (element['json'] != "") {
                        fs.readFile('templates' + separator + element['id_template'] + '.html', 'utf8', function(err, data) {
                            if (err) {
                                return console.log(err);
                                reject(err);
                            }
                            html = data;
                           // filling the template
                            resolve(html);
                        });
                    }
                });
                var makeDirectory = new Promise((resolve, reject) => {
                    if (element['json'] != "") {
                        mkdirp(basePath + element['path'], function(err) {
                            if (err) {
                                reject(err);
                            }
                            resolve(element);
                        });
                    }
                });
    
                var makePDF = (html) => {
                    return new Promise((resolve, reject) => {
                        if (element['json'] != "") {
                            pdf.create(html, options).toFile(basePath + element['path'] + separator + element['filename'], function(err, res) {
                                if (err) {
                                    console.log(err);
                                    reject(err);
                                } else {                                   
                                    var request2 = new sql.Request();
                                    request2.input('flag', sql.Int, 5);
                                    request2.input('id_inventory', sql.Int, element['id_item']);
                                    request2.execute("PDF_create_json", (err2, result2) => {});                                    
                                }
    
                                if (mergeNeeded == 1) {
                                    if ((files.length > 100) || (files.length == size)) {
                                        PDFMerge(files, { output: basePath + mergedName }).then(() => {
                                            files.length = 0;
                                            files.push(basePath + mergedName);
                                            return "OK";
                                        })
                                    }
                                } resolve("OK");
                            });
                        } else {
    
                            if (mergeNeeded == 1) {
                                if ((files.length > 100) || (files.length == size)) {
                                    PDFMerge(files, { output: basePath + mergedName }).then(() => {
                                        files.length = 0;
                                        files.push(basePath + mergedName);
                                        return "OK";
                                    })
                                }
                                console.log("mergedname: " + mergedName);
                                console.log("Files have been merged");
                                resolve("OK");
                            }
                        }
    
                    });
                };
                return makeDirectory
                    .then(() => {
                        return fillTemplate
                    })
                    .then(makePDF)
                    .then(() => {
                        console.log(files);
                    })
            }
    
        ))
    }).then(results => {
        res.end("all done");
    })
    

    });


    person minicooper    schedule 21.05.2018    source источник


    Ответы (1)


    Вам нужно следить за своим потоком управления. Да, вы создаете обещания, но не ждете их выполнения. Вы можете использовать async/await синхронизацию или библиотеку Promise, например bluebird.

    Основная проблема вашего конкретного фрагмента кода — result.recordset.forEach(element => {, который, по сути, запускается синхронно, а затем вызывает res.end().

    Либо вы можете сделать все async/await, но вам может понадобиться Promisify для этого request.execute("create_json", callback) вызова.

    Или вы можете использовать библиотеку Promise, чтобы сделать что-то вроде

    Promise.each(result.recordset, function returnAPromise(){
      // your stuff here. Make sure this returns a Promise (chain)
    })
    .then(results => { 
      // now call res.end() 
    })
    

    чтобы убедиться, что все в вашем массиве обрабатывается в первую очередь. (Вы также захотите catch эту цепочку промисов с res.error() или любым другим вызовом, и убедитесь, что ваши промисы возвращаются, поэтому они успешно связаны цепочкой:

    return makeDirectory.then(() => {
                return fillTemplate.then(result => {
                    return makePDF(result).then(() => {
                         console.log("");
                    });
                });
            });
    

    Или консолидировать

    return makeDirectory
    .then(() => {
       return fillTemplate
    })
    .then(makePDF)
    .then(() => { console.log('here') } )
    

    Это всего лишь отправная точка, но, надеюсь, вы найдете ее полезной.

    person clay    schedule 21.05.2018
    comment
    Я пытался следовать вашему руководству, но теперь возникла проблема: он заполняет массив файлов [], включая все строки, возвращаемые хранимой процедурой. Проверки files.length › 100 не пройдены. Я явно что-то пропустил. Внес правку в исходный пост - person minicooper; 01.06.2018
    comment
    Я тоже с трудом следую! Убедитесь, что makePDF(), resolve('ok') отличается от того, что возвращает 'ok', и не ожидает его. Я бы посоветовал вам добавить много строк console.log в ваш код и запускать только с 1 или 2 файлами. Посмотрите, как выполняется ваш код, и просмотрите каждое значение по мере его обработки, особенно начало каждого '.then()' и вход в каждую функцию. Это позволит вам увидеть, что происходит на самом деле. Надеюсь, у тебя все получится. - person clay; 02.06.2018