异步代码在 Node 和 Express Server 中无序运行

Asynchronous code running out of order with Node and Express Server

提问人:Vibi 提问时间:5/24/2023 更新时间:5/24/2023 访问量:16

问:

我是全栈开发的新手,并且有一个简单的 Express 服务器,它从 HTML 表单中获取输入,然后使用 mysql npm 包查询 mysql 服务器。然后,来自 mysql 服务器的数据被重新格式化为我发送到客户端的对象,以使用 chart.js 制作图表和表格。当我调用函数来查询 mysql 并创建对象时,会出现问题,代码运行无序,并且在我使用 .render 发送对象时对象最终为空白。

索引.js服务器代码:

const express = require('express')
const app = express()
const path = require('path')
var mysql      = require('mysql');
const charts = require('chart.js')
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));

app.set('view engine', 'ejs')
app.set('views', path.join(__dirname, '/views'))
app.use(express.static(path.join(__dirname,'public')))

app.get('/chart', (req,res) => {
    res.render('charttest.ejs')

})
var allData = {}
var tableArr = new Array(0)
async function getTable(tablename,checkedtimes){  //This is the function that connects to mysql 
    var mysql      = require('mysql');            //and creates the objects
    var connection = mysql.createConnection({
    host     : 'localhost',
     user     : 'root',
    password : '####',
    database: '###'
    });
 
    connection.connect();

    const dataList = new Array(checkedtimes.length)
    var count = 0;
    let allTimes =""
    for(i = 0; i < checkedtimes.length; i++){
        allTimes += `\`${checkedtimes[i]}\`,`
    }
    allTimes = allTimes.substring(0,allTimes.length -1)
    connection.query(`SELECT Date,${allTimes} FROM ${tablename}` ,function (error, results, fields) {
        if (error) throw error;
        let dataTimes = new Array(0)
        for(let i = 0; i < results.length; i++){
            dataTimes.push(results[i].Date)
        }
        let sets = new Array(0)
        for(let i = 0; i < checkedtimes.length; i++){
            let tableData = {}
            let obj = {}
            let dataProfit = new Array(0)
            for(let j = 0; j < results.length; j++){
                dataProfit.push(results[j][checkedtimes[i]])
            }
            obj.data = dataProfit
            sets.push(obj)
            tableData.Time = checkedtimes[i]
            tableData.profit = dataProfit.reduce((a,b)=>a+b)
            tableArr.push(tableData)
        }
        allData.datasets = sets
        allData.labels = dataTimes
        console.log("get table:",allData)
        console.log("gettable:",tableArr)
        //allData and tableArr are the final objects to be sent to client side
        
})
}

app.post('/chart', (req,res) => {
    let prem = req.body.prem;
    let maxloss = req.body.loss
    const checkedtimes = req.body.times

    async function asyncTable(tablename,checkedtimes) {
        await getTable(tablename,checkedtimes)
        console.log("INSIDE asyncTable")
        console.log("async table:" ,tableArr)
        console.log("async table:",allData)
        //Sending the objects to a HTML file where the chart and table are displayed
        res.render('linechart.ejs',{allData:allData,tableArr: tableArr}) 
    }

    switch(prem) { //only including one case here just to show the problem
        case '0.75'://
            if(maxloss === "1x"){
                asyncTable("finalprem75loss1x",checkedtimes)
            }
            break;
}

app.listen(3000, () => {
    console.log("LISTENING ON PORT 3000")
})

当我运行这段代码时,当我到达 .render 命令时,这两个对象是空白的。我在代码的不同区域包含了console.logs,以显示对象的值,以尝试理解正在发生的事情,它给了我这个输出:

LISTENING ON PORT 3000
[
  '09:45:00',
  '10:30:00',
  '11:30:00',
  '12:30:00',
  '13:00:00',
  '14:00:00'
]
INSIDE asyncTable
async table: []
async table: {}
get table: {
  datasets: [
    { data: [Array] },
    { data: [Array] },
    { data: [Array] },
    { data: [Array] },
    { data: [Array] },
    { data: [Array] }
  ],
  labels: [
    //A bunch of data
  ]
}
gettable: [
  { Time: '09:45:00', profit: 148.0900000000002 },
  { Time: '10:30:00', profit: 118.05999999999985 },
  { Time: '11:30:00', profit: 82.70999999999984 },
  { Time: '12:30:00', profit: 171.4700000000004 },
  { Time: '13:00:00', profit: 187.71999999999966 },
  { Time: '14:00:00', profit: 161.81999999999996 }
]

这与我的预期完全不符。它首先运行 getTable 函数中的 console.log(checkedtimes),但随后会立即跳到在 asyncTable 函数中运行 console.log,然后再次切换回 getTable 函数。我是异步编程的新手,所以我不确定我是否正确使用异步,但我的目的是让 getTable 函数(这需要一段时间才能运行,所以我假设这就是扰乱执行顺序的原因)在运行 asyncTable 中的下一行并将对象发送到客户端之前先完全运行。

我遇到的另一个问题是,由于执行顺序被搞砸了,我猜 .render 发生在 getTable 完成之前,因此发送到客户端的对象只是空白对象。这显示在 console.logs 中,其中 asyncTable 函数中的对象被打印为空白,即使它们应该在调用 getTable 函数之后出现。如果您需要更多信息或需要我的ejs文件,我也可以提供它们。

Node.js Ajax Express

评论

0赞 jfriend00 5/24/2023
您正在混合和普通回调(使用 )。别这样。因此,您没有有组织的流控制,也无法控制排序。仅使用 promise 进行异步流控制,并将异步回调替换为该 API 的 promise 版本,然后您可以控制事情发生的顺序。awaitconnection.query()

答: 暂无答案