我目前正在学习将Electron用于大学项目。我想做的是从.xlsx文件中读取数据,然后使用chart.js创建图表并显示数据。为此,我正在使用exceljs和chart.js。为此,我编写了多个函数(下面的代码)。我现在的问题是,我尝试返回一个包含一些数据的数组(它创建得很好),但是在其他函数中它只显示为undefined
。
我知道,我的代码不好。老实说,这是完整的意大利面。我只需要使它正常工作,就不必使用漂亮的代码。
这是我用来绘制图表的功能:
function createGraph() {
// Create Canvas if not already created
if (document.getElementById('datacanvas') == null) {
var canvas = document.createElement('canvas');
canvas.setAttribute("id", "datacanvas")
var datadiv = document.getElementById("datadiv");
datadiv.appendChild(canvas);
var ctx = canvas.getContext("2d");
}
else {
var canvas = document.getElementById('datacanvas')
var ctx = canvas.getContext("2d");
}
var labls = ["Januar", "Februar", "März", "April", "Mai", "Juni",
"Juli", "August", "September", "Oktober", "November", "Dezember"];
var datasts = createDatasets();
console.log(datasts);
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: labls,
datasets: datasts
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
我遇到的问题是变量datasts
或更确切地说data
属性,因为数据是不确定的。它是通过以下两个功能创建的:
function createDatasets() {
console.log("createDatasets");
var dataset = [];
var rdbStrom = document.getElementById('rdbStrom');
var rdbGas = document.getElementById('rdbGas');
var rdbWasser = document.getElementById('rdbWasser');
var rdbGesamt = document.getElementById('rdbGesamt');
if (rdbStrom.checked) {
var set = {
label: 'Stromkosten',
data: getDataArray("strom"),
borderColor: '#FF0000',
borderWidth: 1
};
dataset.push(set);
}
if (rdbGas.checked) {
var set = {
label: 'Gaskosten',
data: getDataArray("gas"),
borderColor: '#00FF00',
borderWidth: 1
};
dataset.push(set);
}
if (rdbWasser.checked) {
var set = {
label: 'Wasserkosten',
data: getDataArray("wasser"),
borderColor: '#0000FF',
borderWidth: 1
};
dataset.push(set);
}
if (rdbGesamt.checked) {
;
var set = {
label: 'Gesamtkosten',
data: getDataArray("gesamt"),
borderColor: '#FFFFFF',
borderWidth: 1
};
dataset.push(set);
}
// Wait
setTimeout(() => {
return dataset;
}, 1000);
}
function getDataArray(type) {
console.log("getDataArray");
var data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var period = [];
var start = new Date(document.getElementById('start').value);
var end = new Date(document.getElementById('end').value);
var tmp = new Date(start);
do {
period.push(tmp.toDateString());
tmp.setDate(tmp.getDate() + 1);
} while (tmp <= end)
if (!fs.existsSync('./Data.xlsx')) {
alert("Error finding File 'Data.xlsx'.");
}
else {
switch (type) {
case "strom": {
workbook.xlsx.readFile('./Data.xlsx')
.then(function () {
var worksheet = workbook.getWorksheet('Data');
for (var i = 2; i <= worksheet.rowCount; i++) {
var r = worksheet.getRow(i);
var d = new Date(r.getCell(1).value);
if (period.includes(d.toDateString())) {
var vbr = r.getCell(3).value;
var prc = r.getCell(4).value;
var gprc = r.getCell(5).value;
var tax = r.getCell(6).value;
var kosten = (vbr * prc) + gprc + tax;
data[d.getMonth()] = data[d.getMonth()] + kosten;
}
}
})
break;
}
case "gas": {
workbook.xlsx.readFile('./Data.xlsx')
.then(function () {
var worksheet = workbook.getWorksheet('Data');
for (var i = 2; i <= worksheet.rowCount; i++) {
var r = worksheet.getRow(i);
var date = new Date(r.getCell(1).value);
if (period.includes(date.toDateString())) {
var vbr = r.getCell(8).value;
var prc = r.getCell(9).value;
var gprc = r.getCell(10).value;
var tax = r.getCell(11).value;
var kosten = (vbr * prc) + gprc + tax;
data[d.getMonth()] = data[d.getMonth()] + kosten;
}
}
})
break;
}
case "wasser": {
workbook.xlsx.readFile('./Data.xlsx')
.then(function () {
var worksheet = workbook.getWorksheet('Data');
for (var i = 2; i <= worksheet.rowCount; i++) {
var r = worksheet.getRow(i);
var date = new Date(r.getCell(1).value);
if (period.includes(date.toDateString())) {
var vbr = r.getCell(13).value;
var prc = r.getCell(14).value;
var gprc = r.getCell(15).value;
var tax = r.getCell(16).value;
var kosten = (vbr * prc) + gprc + tax;
data[d.getMonth()] = data[d.getMonth()] + kosten;
}
}
})
break;
}
default:
break;
}
}
// Wait till process is done reading file
setTimeout(() => {
console.log("Timeout")
for (i = 0; i < data.length; i++) {
console.log("Data[" + i + " ]: " + data[i]);
}
console.log("Return DataArray");
return data;
}, 1000);
}
同样,我知道我的代码不好,我只需要使它工作即可。 控制台中的输出如下:
createDataset
getDataArray
undefined // This is the datasts Variable which I need to wait for
Timeout // This comes from the third function
// Here it displays the data it read from the Excel file from the third function
答案 0 :(得分:0)
这是由于异步性问题,您在使用createDatasets时就好像它是一个同步函数(例如return 1 + 2),而它依赖于异步操作, 即:
let exampleInt = 0
setTimeout(() => {
// callback
exampleInt = 1;
return dataset;
}, 1000);
// This will be reached before the callback executes, so exampleInt equals 0
您应该查看https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises以实现您的目标,我想在操作结束之前等待操作结束,然后再根据操作结果执行代码
它会让您大开眼界吗?
现在的分辨率,第一个功能: createDatasets
function createDatasets() {
console.log("createDatasets");
var dataset = [];
var rdbStrom = document.getElementById('rdbStrom');
var rdbGas = document.getElementById('rdbGas');
var rdbWasser = document.getElementById('rdbWasser');
var rdbGesamt = document.getElementById('rdbGesamt');
// storing each label we need
let dataArraysNeeded = [];
let dataArraysNeededAsPromises = [];
let designParams = {
"strom": {
title: "Stromkosten",
color: "#FF0000"
},
"gas": {
title: "Gaskosten",
color: "#00FF00"
},
"wasser": {
title: "Wasserkosten",
color: "#0000FF"
},
"gesamt": {
title: "Gesamtkosten",
color: "#FFFFFF"
}
};
if (rdbStrom.checked) {
dataArraysNeeded.push('strom');
}
if (rdbGas.checked) {
dataArraysNeeded.push('gas');
}
if (rdbWasser.checked) {
dataArraysNeeded.push('wasser');
}
if (rdbGesamt.checked) {
dataArraysNeeded.push('gesamt');
}
// From here we have an array of labels (ex: ["wasser","gesamt"])
// We now want to get the data array for each of these labels, here is how it's done
for (let i = 0; i < dataArraysNeeded.length; i++) {
dataArraysNeededAsPromises.push(getDataArray(dataArraysNeeded[i]));
}
// This will execute all the promises AND WAIT the end of the slowest promise
return Promise.all(dataArraysNeededAsPromises).then((sets) => {
let currentLabel = "";
// sets[0] equals getDataArray("wasser") for example
for (let j = 0; j < sets.length; j++) {
currentLabel = dataArrayLabel[j]; // "wasser"
dataset.push( {
label: designParams[currentLabel]["title"],
data: sets[j],
borderColor: designParams[currentLabel]["color"],
borderWidth: 1
});
}
return dataset; // Array of objects {label, data, borderColor, borderWidth}
});
}
有关Promise.all的工作原理,请参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
您的主函数 createGraph ,该函数调用createDatasets(您可以看到如何消耗返回承诺的函数的结果)
function createGraph() {
// Create Canvas if not already created
if (document.getElementById('datacanvas') == null) {
var canvas = document.createElement('canvas');
canvas.setAttribute("id", "datacanvas")
var datadiv = document.getElementById("datadiv");
datadiv.appendChild(canvas);
var ctx = canvas.getContext("2d");
}
else {
var canvas = document.getElementById('datacanvas')
var ctx = canvas.getContext("2d");
}
var labls = ["Januar", "Februar", "März", "April", "Mai", "Juni",
"Juli", "August", "September", "Oktober", "November", "Dezember"];
// Here you instanciate your promise of Dataset, which IS NOT synchronous
var datasetPromise = createDatasets();
// So you need to specifiy a callback, executed on promise completion
return datasetPromise.then((yourDatasetReadyToBeUsed) => {
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: labls,
datasets: yourDatasetReadyToBeUsed
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
return 'completed !';
});
}
我会让您找到最后一个,因为它与这两个函数非常相似(getDataArray在读取文件时也需要返回Promise)! 对您来说更清楚吗?