You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chart.js 3.8.0 折线图定时更新数据后无法显示问题排查

代码错误点与修复方案

你的代码存在4个核心问题,按影响优先级排序:

  • 字段名不符合Chart.js规范:Chart.js 接收的数据集配置字段为复数形式datasets,你写的是单数dataset,图表初始化时根本读不到数据系列配置,这是最核心的不显示原因。同时标签数组labels是挂载在data配置下,不是config根属性,你之前传参给setLabels时路径写错误读了undefined。
  • 异步请求时序错误:你封装的getPriceData__是回调风格的XHR请求,没有返回Promise对象,外层加await完全无法等待请求返回。实际执行时定时器里调用getPriceData()后会立刻执行后续的pop、更新图表逻辑,此时接口数据还没存入chartCryptoData数组,大部分时候取到的都是空值。
  • 数组裁剪逻辑错误:你初始化的labels和价格数据数组都是空数组,每次push新值之后立刻调用shift()删除数组首项——空数组push后长度为1,shift后长度直接回到0,数组永远存不下可渲染的数据点,相当于加了数据又立刻删掉。
  • PHP输出未做转义:直接把Session变量输出到JS字符串中,如果变量包含引号、特殊字符会直接触发JS语法错误,应该用json_encode做安全转义。

修复后核心代码

<div>
    <canvas class="realTimeGraph" id="realTimeGraph"></canvas>
</div>
<script type="text/javascript">
    var ctx = document.getElementById("realTimeGraph").getContext('2d');
    const BaseUrl = "http://localhost:3000/CryptoSite/php/dbEndpoint.php?crypto="
    // 配置图表最多展示的点位数量,初始化时预填空值避免shift清空全部数据
    const maxDataPoint = 10;
    let chartCryptoData = [];
    let data = {
        labels: Array(maxDataPoint).fill(''),
        // 修正字段名为datasets(复数)
        datasets: [{
            label: "Crypto price",
            data: Array(maxDataPoint).fill(null),
            backgroundColor: 'rgb(255, 99, 132)',
            borderColor: 'rgb(255, 99, 132)',
            tension: 0.1
        }]
    };
    const config = {
        type: 'line',
        data : data,
        options : {}
    };

    // 将XHR封装为Promise形式,让await可以正常等待请求完成
    function getPriceData__(url) 
    {
        return new Promise((resolve, reject) => {
            const xhttp = new XMLHttpRequest();
            xhttp.open("GET", url, true);
            xhttp.responseType = 'json';
            xhttp.send();

            xhttp.onload = () => {
                var status = xhttp.status;
                if (status === 200) {
                    resolve(xhttp.response);
                } else {
                    reject(status);
                }
            };
            xhttp.onerror = () => reject(xhttp.status);
        })
    }

    async function getPriceData() {
        // 用json_encode转义PHP输出,避免特殊字符触发JS语法错误
        let cryptoForGraph = <?php echo json_encode($_SESSION['cryptoForGraph'] ?? '');?>;
        let url = BaseUrl + cryptoForGraph
        try {
            const res = await getPriceData__(url);
            chartCryptoData.push({
                x: res['timestamp'],
                y: res['price']
            });
        } catch (err) {
            console.log('Something went wrong: ' + err);
        }
    }

    function setLabels(labels, timestamp) {
        labels.push(timestamp);
        // 数组长度超过上限再删除旧数据,避免清空全部点位
        if (labels.length > maxDataPoint) labels.shift();
    }

    function setData(data, price) {
        data.push(price);
        if (data.length > maxDataPoint) data.shift();
    }

    document.getElementById("showCryptoGraph").onclick = async () => {
        console.log("button press");

        var myLineChart = new Chart(ctx, config);
        // 首次加载先拉取一次数据,无需等第一个5秒周期
        await getPriceData();

        setInterval( async () => {
            await getPriceData();
            let currentData = chartCryptoData.pop();
            if(currentData !== undefined)
            {
                // 修正labels、datasets的读取路径,从config.data下取值
                setData(config.data.datasets[0].data, currentData.y);
                setLabels(config.data.labels, currentData.x);

                myLineChart.update();
                console.log("end interval");
            }
        }, 5000);
    };
</script>

修复逻辑说明:初始化时提前给labels和data数组填充固定长度的空值,只有当数组长度超过最大展示点位数量时才执行shift删除旧数据,保证图表始终有可渲染的连续数据;把XHR请求改成Promise形式后,await可以正确等待接口返回再执行后续更新逻辑,不会出现取空值的问题。

内容的提问来源于stack exchange,提问作者EvoKin17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:06:22