首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向数据库项目发送HTML报告

向数据库项目发送HTML报告
EN

Code Review用户
提问于 2020-09-25 10:22:20
回答 1查看 74关注 0票数 1

因此,我最近一直专注于前端、数据验证、显示错误等方面,并非常感谢CertainPerformance为我做了许多评论:)

我使用handlebars创建了一个报表模板,创建了一个MySQL数据库来存储数据,使用Node JS在2之间进行交互。现在我已经了解了Node如何与前端交互,获取数据并将其发送到数据库。

我想听听对我当前代码前端和后端的一些评论。对我个人来说,这是可行的,我非常高兴我能创造出这样的东西,而以前我从未想过我能:D。

我只想听听一些评论--在哪里我可以进步,在哪里我缺乏什么,什么东西可以简化等等。

Node JS

注意:这个函数是在路由阶段触发的,我还没有在这里包含它。

代码语言:javascript
复制
// 21-TEMP-01a
exports.TEMP01A21 = async function(req, res) {

    // Array to store actual temperature
    var actualTemp = [];
    // Array to store minimum temperature
    var minTemp = [];
    // Array to store maximum temperature
    var maxTemp = [];

    // Array to store actual humidity
    var actualHumid = [];
    // Array to store minimum humidity
    var minHumid = [];
    // Array to store maximum humidity
    var maxHumid = [];

    // Get drying room names
    var roomNames = [];



    // Loop thorugh each req.body values
    for(var key in req.body) {
        // Store req.body key to value var
        var value = req.body[key];

        // For each key that starys with ActualTemp store into array
        if(key.startsWith("actualtemp")) {
            actualTemp.push(value);
        }

        // minTemp
        if(key.startsWith("mintemp")) {
            minTemp.push(value);
        }

        // maxTemp
        if(key.startsWith("maxtemp")) {
            maxTemp.push(value);
        }

        // actualHumidity
        if(key.startsWith("actualhumid")) {
            actualHumid.push(value);
        }

        // minHumidity
        if(key.startsWith("minhumid")) {
            minHumid.push(value);
        }

        // maxHumidity
        if(key.startsWith("maxhumid")) {
            maxHumid.push(value);
        }

        // Room Names
        if(key.startsWith("dryingroom")) {
            roomNames.push(value);
        }
        
    }


    // Get todays date
    var today = new Date();
    // Format the date
    var formatDay = today.toISOString().substring(0, 10);

    // Create an array to create custom MySQL query
    var values = [];

    // For each temperature value, store its output to values array
    for(var i = 0; i < actualTemp.length; i++) {
    values.push([roomNames[i] , actualTemp[i],
                minTemp[i], maxTemp[i],
                actualHumid[i], minHumid[i],
                maxHumid[i], formatDay, 
                res.locals.user.id]);
    }

    db.query("insert into 21TEMP01a (room_name, actual_temperature, min_temperature, max_temperature, actual_humidity, min_humidity, max_humidity, time, user) values ?", [values], (error, result) => {
        if(error) {
            console.log(error);
       }
       else{
           res.redirect('/reports/daily');
       }
     });
}

前端

代码语言:javascript
复制
    Form:
    

        

            Select Room
            
                 
                    
                    Drying Room 1
                    
                    Drying Room 2
                    
                    Dry Store
                
            
            
            

                
                
                    
                    Drying Room 1
                    

                    
                    
                     
                        Temperature °C - Actual
                        

                      
                        Temperature °C - Minimum
                        

                    
                        Temperature °C - Maximum
                        
                    
                    

                    

                    
                    
                         
                        Relative Humidity - Actual
                        
                        
                        Relative Humidity - Minimum
                        
                         
                        Relative Humidity - Maximum
                        
                    
                


                
                
                    
                    Drying Room 2
                    

                    
                    
                       
                        Temperature °C - Actual
                        

                       
                        Temperature °C - Minimum
                        

                       
                        Temperature °C - Maximum
                        
                    
                    

                    

                    
                    
                         
                        Relative Humidity - Actual
                        
                        
                        Relative Humidity - Minimum
                        
                         
                        Relative Humidity - Maximum
                        
                    
                

                
                
                    
                    Dry Store
                    

                    
                    
                        
                        Temperature °C - Actual
                        

                        
                        Temperature °C - Minimum
                        

                        
                        Temperature °C - Maximum
                        
                    
                    

                    

                    
                    
                         
                        Relative Humidity - Actual
                        
                         
                        Relative Humidity - Minimum
                        
                         
                        Relative Humidity - Maximum
                        
                    
                

                
                    Please complete all required fields
                

                Submit
            
            
        
    







  
    
      
        Targets not met
        
          ×
        
      
      
        Some temperatures or humidity values have not met their targets.
        - Re-check or continue submitting current data.
      
      
        Submit
        Close
      
    
  




// Store DOM Strings
var DOMStrings = {
    room_options: '#RoomMenu'
};

// On selected option, show specific div element
showActiveElement = () => {
    

    for(const option of document.querySelector(DOMStrings.room_options).options) {
        document.querySelector(`#${option.value}`).style.display = "none";
    }

    if(document.querySelector(DOMStrings.room_options).value === 'dry-1') {
        document.querySelector('#dry-1').style.display = "block";
    } else if (document.querySelector(DOMStrings.room_options).value === 'dry-2') {
        document.querySelector('#dry-2').style.display = "block";
    } else if (document.querySelector(DOMStrings.room_options).value === 'dry-3') {
        document.querySelector('#dry-3').style.display = "block";
    }

}



// Show selected div element from options
document.querySelector(DOMStrings.room_options).addEventListener('change', () => {
    showActiveElement();
});


// Validate data
document.getElementById("form").addEventListener("submit", (e) => {
        
    const inputs = document.querySelectorAll('#form input');
    
    let bool;
        // 1. Check if input fields are empty
        const empty = [].filter.call(inputs, e => e.value === "");

        let notEmpty;

        if(empty.length === 0) {
            notEmpty = true;
        } else {
            e.preventDefault();

            document.getElementById('errors').style.opacity = 1;
     
            empty.forEach(element => {
                element.style.borderColor = "red";
                element.placeholder = "Required";
                element.addEventListener("input", (e) => {
                    if(element.value === "") {
                        bool = false;
                        element.style.borderColor = "red";
                        element.placeholder = "Required";
                    } else {
                        element.style.borderColor = "#fff";
                    }

                    const empty = [].filter.call(inputs, e => e.value === "");

                    if(empty.length === 0) {
                        document.getElementById('errors').style.opacity = 0;
                    } else {
                        document.getElementById('errors').style.opacity = 1;
                    }
                });
            });
        }

    // Validate Temperature and humidity values
    if(notEmpty == true) {
        for (var i = 0; i < inputs.length; i++) {

            // Validate Temperatures for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)-temp-(1|2)$/)) {
                validateTempDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Humidity for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)humid(1|2)$/)) {
                validateHumidityDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Temp. for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)temp(3)$/)) {
                validateTempDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate humidity for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)humid(3)$/)) {
                validateHumidityDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }
        }
    }
});


function validateTempDryingRoom(value, item, e) {

    if(value < 39.4 || value > 49) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal();
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateHumidityDryingRoom(value, item ,e) {

    if(value < 14 || value > 30) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal(); 
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateTempDryStore(value, item, e) {
    if(value < 10 || value > 27.2) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal();
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateHumidityDryStore(value, item ,e) {

    if(value < 40 || value > 70) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal(); 
    } else {
        item.style.backgroundColor = '#fff';
    }
}

document.getElementById('submit-email').addEventListener('click', () => {
    const form = document.getElementById('form');
    form.submit();
});


// On load
window.onload = () => {
    showActiveElement();
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-09-27 09:54:15

首先,您的代码似乎是全局的,我在这里要写的大部分内容都是详细的。当然,这也反映了我个人的观点。虽然我尽量不讨论关于我个人意见的观点,但我的个人意见可能会影响我认为一般性的问题。

关于评论

远离我的想法,不鼓励您评论您的代码,但注释可能并不总是一个好主意。

您可能已经了解到注释代码是好的,这是显而易见的,很明显,您甚至不明白为什么注释可能会损害您的代码。在注释代码时,您可能看到的唯一缺点是您花了时间进行注释。

好吧,如果你再也不回你的代码,你不需要评论它。好吧,大多数代码都是“维护”和发展的。这就是问题所在。一般来说,当代码发生变化时,代码周围的注释往往不会改变。当代码中有问题时,您将更正代码,直到问题解决为止。当评论中有问题时,什么也不会做,因为没有人会注意到。

此外,评论应该是有意义的。通常,您可以用正确的变量/函数/类名称替换一些无用的注释。一个例子(这比您的代码要糟糕得多,但是要显示真正的区别)

代码语言:javascript
复制
// store an empty array in the variable a
let a = [];

// [...]

// if the string k starts with "at", append the content of the value v at the end of the array a
if (k.startsWith("at")) {
    a.push(v);
}

现在将其与以下未注释的代码进行比较:

代码语言:javascript
复制
let actualTemperatureArray = [];

// [...]

if (queryParameterKey.startsWith("actualTemperature")) {
    actualTemperatureArray.push(value);
}

其思想是,变量的名称应该反映变量所做的事情。如果是的话,你就不用评论了。“解析”代码也是如此。查看查询参数键并查看它是否以某个字符串开头的事实是显而易见的,这就是代码的字面意思。一个有趣的评论不是你在做什么,而是你为什么要这么做。如果不明显的话。如果这是显而易见的,也许这个评论是无用的。

但请评论你的技巧。例如,如果因为“第一个值应该被忽略”而跳过一个循环中的一个值,则应该对其进行注释。这里有一个技巧是未来读者必须知道的。

但是,您可能仍然希望对变量声明进行注释。因此,如果您这样做,至少使用JSDoc (https://jsdoc.app/)。JSDoc允许您添加一些静态类型定义,即:

  • 类型检查器可用于验证javascript (类似于静态类型语言)。
  • 用于现代IDE (可视化代码、WebStorm等)若要提供有关代码的信息,请执行以下操作。

现在让我们从您的代码中学习示例。

代码语言:javascript
复制
    // Array to store actual temperature
    var actualTemp = [];

你认为actualTemp是否足以让人理解变量的作用?我不是说不是。但你得自己决定。我将采取保守的观点,并认为actualTemperatureArray更好(但是更好地了解上下文,也许在您的领域中,临时是足够的,没有人会认为在那个上下文中,它可能意味着临时的)。

而且,由于actualTemperatureArray包含您所需的所有含义,所以没有必要使用注释。

代码语言:javascript
复制
    var actualTemperatureArray = [];

当然,你会把实际的温度存储在这个数组中。没必要说出来。

但是,如果您想说,请使用JSDoc。

代码语言:javascript
复制
    /** @type {string[]} Array to store actual temperature */
    var actualTemperatureArray = [];

在您的代码中,当我将光标放在actualTemp上时,VS代码将向我展示以下工具提示:

代码语言:javascript
复制
(local var) actualTemp: any[]

所以我知道这个变量是一个局部变量,它是一个数组,我不知道是什么。

在最后一个示例中,当我将光标放在actualTemperatureArray上时,将向我展示以下工具提示:

代码语言:javascript
复制
(local var) actualTemperatureArray: string[]
@type — {string[]} Array to store actual temperature

这就是说,我不想阻止您发表评论,而是想一想,您可以为读者带来哪些代码不是显而易见的提供的。如果您只是重复代码所述的内容,则可能没有必要对其进行注释。如果你能洞察你为什么这么做,这可能是一个有帮助的评论。

重复

下面的块通常有很多类似的行:

代码语言:javascript
复制
        // For each key that starys with ActualTemp store into array
        if (key.startsWith("actualtemp")) {
            actualTemperatureArray.push(value);
        }

        // minTemp
        if (key.startsWith("mintemp")) {
            minimalTemperatureArray.push(value);
        }

        // maxTemp
        if (key.startsWith("maxtemp")) {
            maximalTemperatureArray.push(value);
        }

        // actualHumidity
        if (key.startsWith("actualhumid")) {
            actualHumidityArray.push(value);
        }

        // minHumidity
        if (key.startsWith("minhumid")) {
            minimalHumidityArray.push(value);
        }

        // maxHumidity
        if (key.startsWith("maxhumid")) {
            maximalHumidityArray.push(value);
        }

        // Room Names
        if (key.startsWith("dryingroom")) {
            roomNames.push(value);
        }

对此进行分解可能是个好主意。

每个块操作一个不同的变量。因此,让我们创建一个包含所有这些变量的对象,这样在访问这些数组变量时我们就可以更加通用。

我们需要一个数据结构来“描述”我们需要的数据。我认为像"actualtemp""mintemp"这样的名字是协议的一部分,是不能更改的。

我可以用它作为索引,但我会使用更显式的名称,但这部分可以简化。

我们首先创建一个描述我们需要的数据的结构(注意,订单很重要,它是查询中的一个,因为稍后我将重用该顺序来创建查询)。

代码语言:javascript
复制
    /**
     * @type {Object.} The prefix of all body.req referenced by the name of the parameter
     */
    var paramKeyPrefixesByParamName = {
        roomName: "dryingroom",
        actualTemperature: "actualtemp",
        minimalTemperature: "mintemp",
        maximalTemperature: "maxtemp",
        actualHumidity: "actualhumid",
        minimalHumidity: "minhumid",
        maximalHumidity: "maxhumid",
    };
    /** @type{string[]} The parameter names */
    const parameterNames = Object.keys(paramKeyPrefixesByParamName);

现在让我们创建数组:

代码语言:javascript
复制
    /**
     * @type {Object.} The array of values for each parameter, indexed by the name of the parameter
     */
    var valueArraysByParamName = {};

我还没有在这里创建数组,稍后再创建它们。我本可以在这里做的。

代码语言:javascript
复制
    // Loop thorugh each req.body values
    for (var key in req.body) {
        // Store req.body key to value var
        var value = req.body[key];

        // We iterate over all the
        // parameter names
        // (roomName, actualTemperature, ...)
        parameterNames.forEach((parameterName) => {
            // We extract the prefix
            // from the parameter names
            // (dryingroom, actualtemp, ...)
            const prefix = paramKeyPrefixesByParamName[parameterName];
            if (key.startsWith(prefix)) {
                // We make sure the array exists.
                // If it doesn't exist, we create it.
                if (! valueArraysByParamName[parameterName]) {
                    valueArraysByParamName[parameterName] = [];
                }
                // We append the value in the correct array.
                valueArraysByParamName[parameterName].push(value);
            }
        })
    }

现在我们可以创建查询:

代码语言:javascript
复制
    /** @type {string[][]} An array to create custom MySQL query */
    var values = [];

    // For each temperature value, store the values associated to that temperature
    for (var i = 0; i < actualTemperatureArray.length; i++) {
        values.push([
            ...parameterNames.map((parameterName)=>valueArraysByParamName[parameterName][i]),
            formatDay,
            res.locals.user.id
        ]);
    }

现在,服务器代码看起来如下:

代码语言:javascript
复制
// 21-TEMP-01a
exports.TEMP01A21 = async function (req, res) {

    /**
     * @type {Object.} The prefix of all body.req referenced by the name of the parameter
     */
    var paramKeyPrefixesByParamName = {
        roomName: "dryingroom",
        actualTemperature: "actualtemp",
        minimalTemperature: "mintemp",
        maximalTemperature: "maxtemp",
        actualHumidity: "actualhumid",
        minimalHumidity: "minhumid",
        maximalHumidity: "maxhumid",
    }
    /**
     * @type {Object.} The array of values for each parameter, indexed by the name of the parameter
     */
    var valueArraysByParamName = {};

    // Loop thorugh each req.body values
    for (var key in req.body) {
        // Store req.body key to value var
        var value = req.body[key];

        // We iterate over all parameter names (roomName, actualTemperature, ...)
        Object.keys(paramKeyPrefixesByParamName).forEach((parameterName) => {
            // We extract the prefix from the parameter name (dryingroom, actualtemp, ...)
            const prefix = paramKeyPrefixesByParamName[parameterName];
            if (key.startsWith(prefix)) {
                // We make sure the array exists. If it doesn't exist, we create it.
                if (! valueArraysByParamName[parameterName]) {
                    valueArraysByParamName[parameterName] = [];
                }
                // We append the value in the correct array.
                valueArraysByParamName[parameterName].push(value);
            }
        })
    }


    // Get todays date
    var today = new Date();
    // Format the date
    var formatDay = today.toISOString().substring(0, 10);

    /** @type {string[][]} An array to create custom MySQL query */
    var values = [];

    // For each temperature value, store the values associated to that temperature
    for (var i = 0; i < actualTemperatureArray.length; i++) {
        values.push([
            ...Object.keys(paramKeyPrefixesByParamName).map((parameterName)=>valueArraysByParamName[parameterName][i]),
            formatDay,
            res.locals.user.id
        ]);
    }

    db.query("insert into 21TEMP01a (room_name, actual_temperature, min_temperature, max_temperature, actual_humidity, min_humidity, max_humidity, time, user) values ?", [values], (error, result) => {
        if (error) {
            console.log(error);
        }
        else {
            res.redirect('/reports/daily');
        }
    });
}

前侧

的重复

在前面,你有一些重复:

代码语言:javascript
复制
function validateTempDryingRoom(value, item, e) {

    if(value < 39.4 || value > 49) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal();
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateHumidityDryingRoom(value, item ,e) {

    if(value < 14 || value > 30) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal(); 
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateTempDryStore(value, item, e) {
    if(value < 10 || value > 27.2) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal();
    } else {
        item.style.backgroundColor = '#fff';
    }
}

function validateHumidityDryStore(value, item ,e) {

    if(value < 40 || value > 70) {
        e.preventDefault();
        item.style.backgroundColor = 'red';
        $("#myModal").modal(); 
    } else {
        item.style.backgroundColor = '#fff';
    }
}

好像你一次又一次地做同样的事。

我们重写这个吧。

代码语言:javascript
复制
function createValidateElement(minValue, maxValue) {
    return function (value, item, e) {

        if(value < minValue || value > maxValue) {
            e.preventDefault();
            item.style.backgroundColor = 'red';
            $("#myModal").modal();
        } else {
            item.style.backgroundColor = '#fff';
        }
    }
}

const validateTempDryingRoom = createValidateElement(39.4, 49);
const validateHumidityDryingRoom = createValidateElement(14, 30);
const validateTempDryStore = createValidateElement(10, 27.2);
const validateHumidityDryStore = createValidateElement(40, 70);

我创建了一个创建函数的函数。

小心,因为validateTempDryingRoomvalidateHumidityDryingRoomvalidateTempDryStorevalidateHumidityDryStore现在都是经典变量,而不是函数,所以在使用之前应该声明它们。

但是,这些验证器的使用也是重复的:

代码语言:javascript
复制
            // Validate Temperatures for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)-temp-(1|2)$/)) {
                validateTempDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Humidity for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)humid(1|2)$/)) {
                validateHumidityDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Temp. for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)temp(3)$/)) {
                validateTempDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate humidity for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)humid(3)$/)) {
                validateHumidityDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }

所以我们需要一个数据结构来描述重复的项目。

代码语言:javascript
复制
const dryDatas = {
    TempDryingRoom: {
        pattern: /^(actual|min|max)-temp-(1|2)$/,
        minValue: 39.4,
        maxValue: 49,
    },
    HumidityDryingRoom: {
        pattern: /^(actual|min|max)humid(1|2)$/,
        minValue: 14,
        maxValue: 30,
    },
    TempDryStore: {
        pattern: /^(actual|min|max)temp(3)$/,
        minValue: 10,
        maxValue: 27.2,
    },
    HumidityDryStore: {
        pattern: /^(actual|min|max)humid(3)$/,
        minValue: 40,
        maxValue: 70,
    },
}

然后我们可以创建验证器:

代码语言:javascript
复制
const dryDataValidators = Object.fromEntries(Object.entries(dryDatas).map(([dryDataKey,dryDataValue])=>[dryDataKey, createValidateElement(dryDataValue.min, dryDataValue.max)]));

如果您认为它不可读,您可以使用一些更易读的:

代码语言:javascript
复制
const dryDataValidators = {};
for (let dryDataKey of Object.keys(dryDatas)) {
    const dryDataValue = dryDatas[dryDataKey];
    dryDataValidators[dryDataKey] = createValidateElement(dryDataValue.min, dryDataValue.max);
}

做同样的事..。

然后替换

代码语言:javascript
复制
    // Validate Temperature and humidity values
    if(notEmpty == true) {
        for (var i = 0; i < inputs.length; i++) {

            // Validate Temperatures for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)-temp-(1|2)$/)) {
                validateTempDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Humidity for Drying room 1 & 2
            if(inputs[i].name.match(/^(actual|min|max)humid(1|2)$/)) {
                validateHumidityDryingRoom(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate Temp. for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)temp(3)$/)) {
                validateTempDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }

            // Validate humidity for Dry Store
            if(inputs[i].name.match(/^(actual|min|max)humid(3)$/)) {
                validateHumidityDryStore(parseFloat(inputs[i].value), inputs[i], e);
            }
        }
    }

通过

代码语言:javascript
复制
    // Validate Temperature and humidity values
    if(notEmpty == true) {
        for (var i = 0; i < inputs.length; i++) {
            // Iterate over all type of dryDatas (TempDryingRoom, HumidityDryingRoom, TempDryStore, ...)
            for (let dryDataKey of Object.keys(dryDatas)) {
                const pattern = dryDatas[dryDataKey].pattern;
                const validator = dryDataValidators[dryDataKey];
                if(inputs[i].name.match(pattern)) {
                    validator(parseFloat(inputs[i].value), inputs[i], e);
                }
            }
        }
    }
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/249831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档