同步调用:第一个函数执行完成后调用第二个函数

Synchronous Call : Call 2nd function after 1st function is executed completely

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

正在尝试编写 XML parser/validator 以根据存储在 excel sheet 中的值/xpath 验证 xml 架构和值。

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

var mocha = require('mocha');
var assert = require('chai').assert;
var fs = require('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 = require('colors');
require('/xmlValidator/dbConnect.js');

var map = new HashMap();
var elementMap = new HashMap();
var resultValue;

//console.log('hello'.green);

map.set("PASS", 0);
map.set("FAIL", 0);
map.set("INVALID_PATH", 0);

function computeResult(elementPath, result) {
  var pass = map.get("PASS");
  var fail = map.get("FAIL");
  var invalidPath = map.get("INVALID_PATH");

  elementMap.set(elementPath, result);

  if (result == "PASS") {
    pass++;
    map.set("PASS", pass);
  } else if (result == "FAIL") {
    fail++;
    map.set("FAIL", fail);
  } else {
    invalidPath++;
    map.set("INVALID_PATH", invalidPath)
  }
  printResult();
}

function printResult() {
  var pass = map.get("PASS");
  var fail = map.get("FAIL");
  var invalidPath = map.get("INVALID_PATH");
  console.log(("PASS Count :" + pass).green);
  console.log(("FAIL Count :" + fail).red);
  console.log(("Inavlid Path :" + invalidPath).yellow);
  elementMap.forEach(function(value, key) {
    if (value == "INVALID_PATH")
      console.log((key + ":" + value).yellow);
    else if (value == "FAIL")
      console.log((key + ":" + value).red);
    else
      console.log(key + ":" + value);
  });

}


var workbook = new Excel.Workbook();
workbook.xlsx.readFile('utils/' + process.argv[2])
  .then(function() {
    var worksheet = workbook.getWorksheet(1);
    worksheet.eachRow(function(row, rowNumber) {
      //console.log(rowNumber);
      var row = worksheet.getRow(rowNumber);
      var dataPath1 = row.getCell("A").value;
      var dataPath2 = row.getCell("B").value;
      var dataPath = dataPath1 + dataPath2;
      //console.log(dataPath);
      var dataValue = row.getCell("D").value;
      var flag = row.getCell("E").value;
      //console.log(flag)
      //console.log(dataValue);
      if (!flag)
        validate(dataPath, dataValue, rowNumber);

      //else console.log("NOT EXECUTED" + rowNumber)

    });


  })

function validate(dataPath, dataValue, rowNumber) {
  var fail = 0;
  fs.readFile('utils/' + process.argv[3], 'utf8', function(err, data) {
    if (err) {
      console.log("ERROR ERROR ERROR ERROR ");
      return console.log(err);
    }
    var doc = new dom().parseFromString(data);
    var subId = String(xpath.select1(dataPath, doc));
    if (subId == "undefined") {
      /*console.log('undefined caught');
      console.log("row number :" + rowNumber);*/
      var resultValue = "INVALID_PATH";
      computeResult(dataPath, resultValue);
    } else {
      var subId = xpath.select1(dataPath, doc);
      var value = subId.lastChild.data;
      /*console.log("row number :" + rowNumber);
      console.log("actual value: " + value);
      console.log("expected value:" + dataValue );*/

      if (dataValue == null) {
        assert.notEqual(value, dataValue, "value not found");
        resultValue = "PASS";
        computeResult(dataPath, resultValue);
      } else {
        if (value == dataValue)
          resultValue = "PASS";
        else resultValue = "FAIL";
        computeResult(dataPath, resultValue);
      }
    }
  });
}

在上面的代码中,我想在验证函数完全执行后调用 printResult() 函数 (workbook.xlsx.readFile)

谁能帮我看看如何使用 done () 函数或进行同步调用?

如果fs.readFileAsync('utils/' + process.argv[3], 'utf8')可以执行一次,那么validate()将是完全同步的,在验证循环之后调用printResult()将是微不足道的。

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

var promise1 = workbook.xlsx.readFile();
var promise2 = fs.readFileAsync(); // requires `fs` to be promisified. 

...在开始验证循环之前。

Promise.all([promise1, promise2]).spread(/* verify here */);

还可以考虑进行大量整理,特别是:

  • 建立 "PASS"、"FAIL" 和 "INVALID_PATH" 作为常量以避免大量重复创建字符串,
  • 使用 js 普通对象代替 hashmap
  • 在打印函数中从 elementMap 构建 map
  • validate()return它的结果并在主例程中构建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);
});

未经测试,所以可能不会 运行,但至少您可以从代码中寻找灵感。