Node.js 同步调用:在第一个函数完全执行后调用第二个函数

Node.js 同步调用:在第一个函数完全执行后调用第二个函数,node.js,callback,promise,synchronous,Node.js,Callback,Promise,Synchronous,我最近提到了node.js中的编码,这可能是一个非常简单的问题。 尝试编写XML解析器/验证器,以根据excel工作表中存储的值/xpath验证XML模式和值 现在,一旦验证函数完成,我想调用printResult函数来打印最终结果。但是,如果我尝试在第一个函数之后立即调用该函数。。它的打印变量为初始值,如果在第一个变量中调用,则会迭代excel工作表中存在的XPath数量,并以增量打印结果 var mocha=require('mocha'); var assert=require('cha

我最近提到了node.js中的编码,这可能是一个非常简单的问题。

尝试编写XML解析器/验证器,以根据excel工作表中存储的值/xpath验证XML模式和值

现在,一旦验证函数完成,我想调用printResult函数来打印最终结果。但是,如果我尝试在第一个函数之后立即调用该函数。。它的打印变量为初始值,如果在第一个变量中调用,则会迭代excel工作表中存在的XPath数量,并以增量打印结果

var mocha=require('mocha');
var assert=require('chai')。assert;
var fs=需要('fs');
var parseString=require('xml2js')。parseString;
var xpath=require('xpath');
var dom=require('xmldom').DOMParser;
var XLSX=require('XLSX');
var Excel=require(“exceljs”);
var should=require('chai')。should();
var HashMap=require('HashMap');
var colors=需要(“颜色”);
需要('/xmlvalidater/dbConnect.js');
var map=newhashmap();
var elementMap=newhashmap();
var结果值;
//log('hello'.green);
map.set(“PASS”,0);
map.set(“失败”,0);
map.set(“无效的_路径”,0);
功能计算机结果(元素路径、结果){
var pass=map.get(“pass”);
var fail=map.get(“fail”);
var invalidPath=map.get(“无效路径”);
elementMap.set(elementPath,result);
如果(结果=“通过”){
pass++;
地图集(“通过”,通过);
}否则如果(结果=“失败”){
失败++;
映射集(“失败”,失败);
}否则{
invalidPath++;
map.set(“无效路径”,invalidPath)
}
printResult();
}
函数printResult(){
var pass=map.get(“pass”);
var fail=map.get(“fail”);
var invalidPath=map.get(“无效路径”);
日志((“通过计数:+PASS).green);
日志((“失败计数:+FAIL).red);
日志(((“Inavlid路径:+invalidPath).yellow);
elementMap.forEach(函数(值、键){
如果(值=“无效路径”)
console.log((key+“:“+value).yellow);
否则如果(值=“失败”)
console.log((key+“:“+value).red);
其他的
console.log(键+”:“+值);
});
}
var workbook=新建Excel.workbook();
workbook.xlsx.readFile('utils/'+process.argv[2])
.然后(函数(){
var工作表=工作簿.getWorksheet(1);
工作表.eachRow(函数(行,行编号){
//console.log(行号);
var row=工作表.getRow(rowNumber);
var dataPath1=row.getCell(“A”).value;
var dataPath2=row.getCell(“B”).value;
var dataPath=dataPath1+dataPath2;
//log(数据路径);
var dataValue=row.getCell(“D”)值;
var标志=行。getCell(“E”)。值;
//console.log(标志)
//console.log(数据值);
如果(!标志)
验证(数据路径、数据值、行数);
//else console.log(“未执行”+行数)
});
})
函数验证(数据路径、数据值、行数){
var fail=0;
fs.readFile('utils/'+process.argv[3],'utf8',函数(err,data){
如果(错误){
日志(“错误”);
返回console.log(err);
}
var doc=new dom().parseFromString(数据);
var subId=String(xpath.select1(dataPath,doc));
如果(子ID==“未定义”){
/*console.log(“未定义捕获”);
console.log(“行号:”+rowNumber)*/
var resultValue=“无效路径”;
计算机结果(数据路径、结果值);
}否则{
var subId=xpath.select1(数据路径,doc);
var value=subId.lastChild.data;
/*console.log(“行号:”+rowNumber);
console.log(“实际值:”+值);
console.log(“预期值:”+dataValue)*/
if(dataValue==null){
assert.notEqual(value,dataValue,“未找到值”);
结果值=“通过”;
计算机结果(数据路径、结果值);
}否则{
如果(值==数据值)
结果值=“通过”;
else resultValue=“失败”;
计算机结果(数据路径、结果值);
}
}
});
}
如果
fs.readFileAsync('utils/'+process.argv[3],'utf8')
可以执行一次,那么
validate()
将完全同步,并且在验证循环之后调用
printResult()
将是微不足道的

在主例程中,您可以简单地聚合两个承诺

var promise1 = workbook.xlsx.readFile();
var promise2 = fs.readFileAsync(); // requires `fs` to be promisified. 
。。。在开始验证循环之前

Promise.all([promise1, promise2]).spread(/* verify here */);
此外,还可以考虑进行一系列清理,特别是:

  • 将“通过”、“失败”和“无效路径”设置为常量,以避免大量重复的字符串创建
  • 使用js普通对象代替hashmap
  • 从打印功能内部的
    elementMap
    构建
    map
  • validate()
    返回其结果并在主例程中构建
    elementMap
这就是整件事,尽我所能的紧。我可能做了一些假设,但希望不会有太多不好的假设

var mocha = require('mocha');
var assert = require('chai').assert;
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs")); // allow Bluebird to take the pain out of promisification.
var parseString = require('xml2js').parseString;
var xpath = require('xpath');
var dom = require('xmldom').DOMParser;
var XLSX = require('xlsx');
var Excel = require("exceljs");
var should = require('chai').should();
// var HashMap = require('hashmap');
var colors = require('colors');
require('/xmlValidator/dbConnect.js');

const PASS = "PASS";
const FAIL = "FAIL";
const INVALID_PATH = "INVALID_PATH";

function printResult(elementMap) {
    var key, result, 
        map = { PASS: 0, FAIL: 0, INVALID_PATH: 0 },
        colorNames = { PASS: 'black', FAIL: 'red', INVALID_PATH: 'yellow' };
    for(key in elementMap) {
        result = elementMap[key];
        map[(result === PASS || result === FAIL) ? result : INVALID_PATH] += 1;
        console.log((key + ": " + result)[colorNames[result] || 'black']); // presumably colors can be applied with associative syntax? If so, then the code can be very concise.
    }
    console.log(("PASS Count: " + map.PASS)[colorNames.PASS]);
    console.log(("FAIL Count: " + map.FAIL)[colorNames.FAIL]);
    console.log(("Inavlid Path: " + map.INVALID_PATH)[colorNames.INVALID_PATH]);
}

function validate(doc, dataPath, dataValue) {
    var subId = xpath.select1(dataPath, doc),
        value = subId.lastChild.data,
        result;
    if (String(subId) == "undefined") {
        result = INVALID_PATH;
    } else {
        if (dataValue === null) {
            assert.notEqual(value, dataValue, "value not found"); // not too sure what this does
            result = PASS;
        } else {
            result = (value === dataValue) ? PASS : FAIL;
        }
    }
    return result;
}

//Main routine
var workbook = new Excel.Workbook();
var promise1 = workbook.xlsx.readFile('utils/' + process.argv[2]); // from the question, workbook.xlsx.readFile() appears to return a promise.
var promise2 = fs.readFileAsync('utils/' + process.argv[3], 'utf8');

Promise.all([promise1, promise2]).spread(function(data2, data3) {
    var worksheet = workbook.getWorksheet(1),
        doc = new dom().parseFromString(data3),
        elementMap = {};
    worksheet.eachRow(function(row, rowNumber) {
        // var row = worksheet.getRow(rowNumber); // row is already a formal variable ??? 
        var dataPath, dataValue;
        if (!row.getCell('E').value)
            dataPath = row.getCell('A').value + row.getCell('B').value;
            dataValue = row.getCell('D').value;
            elementMap[dataPath] = validate(doc, dataPath, dataValue);
    });
    printResult(elementMap);
});

未经测试,因此可能无法运行,但至少可以对代码进行raid以获取想法

是否确实需要调用
fs.readFile('utils/'+process.argv[3],'utf8')
来验证每一行?如果
process.argv[3]
是不变的,那么每次都会返回相同的数据。此外,整个异步问题将大大简化。@Roamer-1888感谢您指出它(我猜是新手犯的错误:)。。将fs.readfile设为blocking并在其后调用printResult.Mmm,blocking方法可能是编码最简单的方法,但不是最好的方法。我会把我的想法贴出来作为答案。