使用vue2+axios+chart.js画折线图 ,出现 RangeError: Maximum call stack size exceeded 错误

目录

效果图

解决方案

修正要点


效果图

修改前App.vue代码:

javascript 复制代码
<template>
    <div id="app">
        <canvas id="myChart"></canvas>
    </div>
</template>

<script>
import axios from 'axios';
import { Chart, registerables } from 'chart.js';
import 'chartjs-adapter-luxon';

Chart.register(...registerables);

export default {
    name: 'App',
    data() {
        return {
            chart: null,
            remainingData: [],
            speedData: []
        };
    },
    mounted() {
        this.fetchData();
        setInterval(this.fetchData, 60000);  // 每分钟更新数据
    },
    methods: {
        fetchData() {
            axios.get('/data.json')
                .then(response => {
                    console.log('接收数据:', response.data);
                    // 确保转换后的时间戳格式正确,使用 new Date(item.timestamp) 而不是 Date(item.timestamp)
                    this.remainingData = response.data.map(item => {
                        return { x: new Date(item.timestamp), y: item.remaining };
                    });
                    this.calculateSpeed();
                    // 确保remainingData和speedData不为空,防止图例点击时出现undefined错误
                    if (this.remainingData.length === 0) {
                        this.remainingData = [{ x: new Date(), y: 0 }];
                    }

                    if (this.speedData.length === 0) {
                        this.speedData = [{ x: new Date(), y: 0 }];
                    }

                    // 防止无限递归调用,只在数据确实有更新时更新图表
                    if (!this.chart) {
                        this.updateChart();
                    } else {
                        // 更新数据并重新渲染
                        this.chart.data.datasets[0].data = this.remainingData;
                        this.chart.data.datasets[1].data = this.speedData;
                        this.chart.update();  // 只更新已有的图表
                    }
                })
                .catch(error => {
                    console.log('获取数据异常:', error);
                });
        },
        calculateSpeed() {
            const speeds = [];
            for (let i = 1; i < this.remainingData.length; i++) {
                const speed = this.remainingData[i].y - this.remainingData[i - 1].y;
                speeds.push({ x: this.remainingData[i].x, y: speed });
            }
            this.speedData = speeds;
        },
        updateChart() {
            this.chart = new Chart(
                document.getElementById('myChart').getContext('2d'),
                {
                    type: 'line',
                    data: {
                        datasets: [
                            {
                                label: 'Remaining',
                                data: this.remainingData,
                                borderColor: 'rgb(75, 192, 192)',
                                tension: 0.1,
                                fill: false
                            },
                            {
                                label: 'Speed',
                                data: this.speedData,
                                borderColor: 'rgb(255, 99, 132)',
                                tension: 0.1,
                                fill: false
                            }
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                type: 'time',  // 使用时间轴
                                time: {
                                    unit: 'minute',  // 设为 minute 使点不聚集
                                    tooltipFormat: 'yyyy-MM-dd HH:mm',
                                    displayFormats: {
                                        minute: 'HH:mm'  // X 轴时间格式化
                                    }
                                },
                                ticks: {
                                    source: 'auto',
                                    autoSkip: true,
                                    maxRotation: 0,  // 防止时间戳旋转
                                }
                            },
                            y: {
                                beginAtZero: true  // 保证 Y 轴从 0 开始
                            }
                        },
                        plugins: {
                            tooltip: {
                                mode: 'index',
                                intersect: false
                            },
                            legend: {
                                onClick: (e, legendItem, legend) => {
                                    const datasetIndex = legendItem.datasetIndex;
                                    const dataset = legend.chart.data.datasets[datasetIndex];

                                    // 确保点击图例时,数据集存在并且被初始化
                                    if (!dataset || !dataset.data || !Array.isArray(dataset.data)) {
                                        console.log('数据集不存在或者未初始化');
                                        return;
                                    }

                                    // 切换数据集的显示状态
                                    dataset.hidden = !dataset.hidden;
                                    legend.chart.update();
                                }
                            }
                        },
                        responsive: true,
                        maintainAspectRatio: false
                    }
                }
            );
        }
    }
}
</script>

出现 RangeError: Maximum call stack size exceeded 错误,可能是由于 setInterval 直接引用了 fetchData,而 fetchData 中又更新了图表或页面元素,导致无限递归问题。每次调用 fetchData 可能会触发多次图表更新,最终导致栈溢出。

为了解决这个问题,你可以通过以下方式优化:

解决方案

  1. 使用箭头函数传递上下文 :避免 setInterval 中的上下文丢失,确保 this 的正确性。
  2. 防止重复图表创建 :在 fetchDataupdateChart 中,确保图表只在需要的时候更新,避免重复调用造成栈溢出。
  3. 处理异步调用 :确保每次 fetchData 的数据处理逻辑正确,避免多个请求导致的图表过度更新。

修改后的App..vue 代码:

javascript 复制代码
<template>
    <div id="app">
        <canvas id="myChart"></canvas>
    </div>
</template>

<script>
import axios from 'axios';
import { Chart, registerables } from 'chart.js';
import 'chartjs-adapter-luxon';

Chart.register(...registerables);

export default {
    name: 'App',
    data() {
        return {
            chart: null,
            remainingData: [],
            speedData: [],
            lastFetchedData: null,  // 存储上次的数据
            intervalId: null  // 存储 setInterval 的 ID
        };
    },
    mounted() {
        this.fetchData();
        this.intervalId = setInterval(this.fetchData, 60000);  // 每分钟更新数据
    },
    beforeUnmount() {
        // 清理定时器,防止组件销毁时继续触发
        if (this.intervalId) {
            clearInterval(this.intervalId);
        }
    },
    methods: {
        fetchData() {
            axios.get('/data.json')
                .then(response => {
                    console.log('接收数据:', response.data);
                    const newData = response.data.map(item => {
                        return { x: new Date(item.timestamp), y: item.remaining };
                    });

                    // 判断数据是否真的有变化,只有在变化时才更新图表
                    if (JSON.stringify(newData) !== JSON.stringify(this.remainingData)) {
                        console.log('数据发生变化,更新图表');
                        this.remainingData = newData;
                        this.calculateSpeed();

                        // 确保remainingData和speedData不为空
                        if (this.remainingData.length === 0) {
                            this.remainingData = [{ x: new Date(), y: 0 }];
                        }

                        if (this.speedData.length === 0) {
                            this.speedData = [{ x: new Date(), y: 0 }];
                        }

                        // 防止无限递归调用,只在数据确实有更新时更新图表
                        if (!this.chart) {
                            this.updateChart();
                        } else {
                            this.chart.data.datasets[0].data = this.remainingData;
                            this.chart.data.datasets[1].data = this.speedData;
                            this.chart.update();  // 只更新已有的图表
                        }
                    } else {
                        console.log('数据未变化,不更新图表');
                    }
                })
                .catch(error => {
                    console.log('获取数据异常:', error);
                });
        },
        calculateSpeed() {
            const speeds = [];
            for (let i = 1; i < this.remainingData.length; i++) {
                const speed = this.remainingData[i].y - this.remainingData[i - 1].y;
                speeds.push({ x: this.remainingData[i].x, y: speed });
            }
            this.speedData = speeds;
        },
        updateChart() {
            this.chart = new Chart(
                document.getElementById('myChart').getContext('2d'),
                {
                    type: 'line',
                    data: {
                        datasets: [
                            {
                                label: 'Remaining',
                                data: this.remainingData,
                                borderColor: 'rgb(75, 192, 192)',
                                tension: 0.1,
                                fill: false
                            },
                            {
                                label: 'Speed',
                                data: this.speedData,
                                borderColor: 'rgb(255, 99, 132)',
                                tension: 0.1,
                                fill: false
                            }
                        ]
                    },
                    options: {
                        scales: {
                            x: {
                                type: 'time',
                                time: {
                                    unit: 'minute',
                                    tooltipFormat: 'yyyy-MM-dd HH:mm',
                                    displayFormats: {
                                        minute: 'HH:mm'
                                    }
                                },
                                ticks: {
                                    source: 'auto',
                                    autoSkip: true,
                                    maxRotation: 0,
                                }
                            },
                            y: {
                                beginAtZero: true
                            }
                        },
                        plugins: {
                            tooltip: {
                                mode: 'index',
                                intersect: false
                            },
                            legend: {
                                onClick: (e, legendItem, legend) => {
                                    const datasetIndex = legendItem.datasetIndex;
                                    const dataset = legend.chart.data.datasets[datasetIndex];

                                    if (!dataset || !dataset.data || !Array.isArray(dataset.data)) {
                                        console.log('数据集不存在或者未初始化');
                                        return;
                                    }

                                    dataset.hidden = !dataset.hidden;
                                    legend.chart.update();
                                }
                            }
                        },
                        responsive: true,
                        maintainAspectRatio: false
                    }
                }
            );
        }
    }
}
</script>

data.json:

bash 复制代码
[
    {
        "remaining": 32.76,
        "timestamp": "2024-09-10 11:51:19"
    },
    {
        "remaining": 32.78,
        "timestamp": "2024-09-10 11:50:14"
    },
    {
        "remaining": 32.81,
        "timestamp": "2024-09-10 11:49:11"
    },
    {
        "remaining": 32.85,
        "timestamp": "2024-09-10 11:48:06"
    },
    {
        "remaining": 32.88,
        "timestamp": "2024-09-10 11:47:02"
    },
    {
        "remaining": 32.9,
        "timestamp": "2024-09-10 11:45:57"
    },
    {
        "remaining": 32.93,
        "timestamp": "2024-09-10 11:44:53"
    },
    {
        "remaining": 32.95,
        "timestamp": "2024-09-10 11:43:49"
    },
    {
        "remaining": 32.98,
        "timestamp": "2024-09-10 11:42:46"
    },
    {
        "remaining": 33.0,
        "timestamp": "2024-09-10 11:41:41"
    },
    {
        "remaining": 33.03,
        "timestamp": "2024-09-10 11:40:36"
    },
    {
        "remaining": 33.05,
        "timestamp": "2024-09-10 11:39:32"
    },
    {
        "remaining": 33.08,
        "timestamp": "2024-09-10 11:38:27"
    },
    {
        "remaining": 33.1,
        "timestamp": "2024-09-10 11:37:22"
    },
    {
        "remaining": 33.13,
        "timestamp": "2024-09-10 11:36:17"
    },
    {
        "remaining": 33.15,
        "timestamp": "2024-09-10 11:35:12"
    },
    {
        "remaining": 33.2,
        "timestamp": "2024-09-10 11:34:07"
    },
    {
        "remaining": 33.22,
        "timestamp": "2024-09-10 11:33:02"
    },
    {
        "remaining": 33.24,
        "timestamp": "2024-09-10 11:31:57"
    },
    {
        "remaining": 33.26,
        "timestamp": "2024-09-10 11:30:52"
    },
    {
        "remaining": 33.29,
        "timestamp": "2024-09-10 11:29:47"
    },
    {
        "remaining": 33.31,
        "timestamp": "2024-09-10 11:28:42"
    },
    {
        "remaining": 33.33,
        "timestamp": "2024-09-10 11:27:37"
    },
    {
        "remaining": 33.36,
        "timestamp": "2024-09-10 11:26:32"
    },
    {
        "remaining": 33.38,
        "timestamp": "2024-09-10 11:25:28"
    },
    {
        "remaining": 33.4,
        "timestamp": "2024-09-10 11:24:23"
    },
    {
        "remaining": 33.43,
        "timestamp": "2024-09-10 11:23:18"
    },
    {
        "remaining": 33.45,
        "timestamp": "2024-09-10 11:22:15"
    },
    {
        "remaining": 33.47,
        "timestamp": "2024-09-10 11:21:12"
    },
    {
        "remaining": 33.52,
        "timestamp": "2024-09-10 11:20:07"
    },
    {
        "remaining": 33.54,
        "timestamp": "2024-09-10 11:19:04"
    },
    {
        "remaining": 33.56,
        "timestamp": "2024-09-10 11:18:02"
    },
    {
        "remaining": 33.57,
        "timestamp": "2024-09-10 11:16:57"
    },
    {
        "remaining": 33.57,
        "timestamp": "2024-09-10 11:15:52"
    },
    {
        "remaining": 33.58,
        "timestamp": "2024-09-10 11:14:47"
    },
    {
        "remaining": 33.59,
        "timestamp": "2024-09-10 11:13:42"
    },
    {
        "remaining": 33.6,
        "timestamp": "2024-09-10 11:12:39"
    },
    {
        "remaining": 33.61,
        "timestamp": "2024-09-10 11:11:34"
    },
    {
        "remaining": 33.62,
        "timestamp": "2024-09-10 11:10:31"
    },
    {
        "remaining": 33.62,
        "timestamp": "2024-09-10 11:09:26"
    },
    {
        "remaining": 33.63,
        "timestamp": "2024-09-10 11:08:21"
    },
    {
        "remaining": 33.64,
        "timestamp": "2024-09-10 11:07:16"
    },
    {
        "remaining": 33.65,
        "timestamp": "2024-09-10 11:06:12"
    },
    {
        "remaining": 33.66,
        "timestamp": "2024-09-10 11:05:07"
    },
    {
        "remaining": 33.67,
        "timestamp": "2024-09-10 11:04:04"
    },
    {
        "remaining": 33.68,
        "timestamp": "2024-09-10 11:03:00"
    },
    {
        "remaining": 33.69,
        "timestamp": "2024-09-10 11:01:55"
    },
    {
        "remaining": 33.7,
        "timestamp": "2024-09-10 11:00:50"
    },
    {
        "remaining": 33.71,
        "timestamp": "2024-09-10 10:59:46"
    },
    {
        "remaining": 33.72,
        "timestamp": "2024-09-10 10:58:41"
    },
    {
        "remaining": 33.72,
        "timestamp": "2024-09-10 10:57:36"
    },
    {
        "remaining": 33.73,
        "timestamp": "2024-09-10 10:56:33"
    },
    {
        "remaining": 33.74,
        "timestamp": "2024-09-10 10:55:30"
    },
    {
        "remaining": 33.75,
        "timestamp": "2024-09-10 10:54:28"
    },
    {
        "remaining": 33.75,
        "timestamp": "2024-09-10 10:53:25"
    },
    {
        "remaining": 33.76,
        "timestamp": "2024-09-10 10:52:20"
    },
    {
        "remaining": 33.76,
        "timestamp": "2024-09-10 10:51:15"
    },
    {
        "remaining": 33.77,
        "timestamp": "2024-09-10 10:50:11"
    },
    {
        "remaining": 33.78,
        "timestamp": "2024-09-10 10:49:06"
    },
    {
        "remaining": 33.78,
        "timestamp": "2024-09-10 10:48:01"
    },
    {
        "remaining": 33.79,
        "timestamp": "2024-09-10 10:46:56"
    },
    {
        "remaining": 33.79,
        "timestamp": "2024-09-10 10:45:51"
    },
    {
        "remaining": 33.8,
        "timestamp": "2024-09-10 10:44:45"
    },
    {
        "remaining": 33.81,
        "timestamp": "2024-09-10 10:43:40"
    },
    {
        "remaining": 33.81,
        "timestamp": "2024-09-10 10:42:35"
    },
    {
        "remaining": 33.82,
        "timestamp": "2024-09-10 10:41:32"
    },
    {
        "remaining": 33.82,
        "timestamp": "2024-09-10 10:40:27"
    },
    {
        "remaining": 33.83,
        "timestamp": "2024-09-10 10:39:24"
    },
    {
        "remaining": 33.83,
        "timestamp": "2024-09-10 10:38:56"
    },
    {
        "remaining": 34.83,
        "timestamp": "2024-09-10 02:12:51"
    },
    {
        "remaining": 34.83,
        "timestamp": "2024-09-10 02:11:44"
    },
    {
        "remaining": 34.84,
        "timestamp": "2024-09-10 02:10:38"
    },
    {
        "remaining": 34.84,
        "timestamp": "2024-09-10 02:09:31"
    },
    {
        "remaining": 34.84,
        "timestamp": "2024-09-10 02:08:28"
    },
    {
        "remaining": 34.85,
        "timestamp": "2024-09-10 02:07:21"
    },
    {
        "remaining": 34.85,
        "timestamp": "2024-09-10 02:06:16"
    },
    {
        "remaining": 34.86,
        "timestamp": "2024-09-10 02:05:11"
    },
    {
        "remaining": 34.86,
        "timestamp": "2024-09-10 02:04:06"
    },
    {
        "remaining": 34.87,
        "timestamp": "2024-09-10 02:03:03"
    },
    {
        "remaining": 34.87,
        "timestamp": "2024-09-10 02:01:58"
    },
    {
        "remaining": 34.87,
        "timestamp": "2024-09-10 02:00:52"
    },
    {
        "remaining": 34.88,
        "timestamp": "2024-09-10 01:59:48"
    },
    {
        "remaining": 34.88,
        "timestamp": "2024-09-10 01:58:43"
    },
    {
        "remaining": 34.89,
        "timestamp": "2024-09-10 01:57:40"
    },
    {
        "remaining": 34.89,
        "timestamp": "2024-09-10 01:56:35"
    },
    {
        "remaining": 34.9,
        "timestamp": "2024-09-10 01:55:30"
    },
    {
        "remaining": 34.92,
        "timestamp": "2024-09-10 01:54:27"
    },
    {
        "remaining": 34.94,
        "timestamp": "2024-09-10 01:53:22"
    },
    {
        "remaining": 34.96,
        "timestamp": "2024-09-10 01:52:18"
    },
    {
        "remaining": 34.98,
        "timestamp": "2024-09-10 01:51:15"
    },
    {
        "remaining": 35.01,
        "timestamp": "2024-09-10 01:50:09"
    },
    {
        "remaining": 35.03,
        "timestamp": "2024-09-10 01:49:02"
    },
    {
        "remaining": 35.05,
        "timestamp": "2024-09-10 01:47:59"
    },
    {
        "remaining": 35.05,
        "timestamp": "2024-09-10 01:46:55"
    },
    {
        "remaining": 35.05,
        "timestamp": "2024-09-10 01:45:50"
    },
    {
        "remaining": 35.06,
        "timestamp": "2024-09-10 01:44:46"
    },
    {
        "remaining": 35.08,
        "timestamp": "2024-09-10 01:43:41"
    },
    {
        "remaining": 35.1,
        "timestamp": "2024-09-10 01:42:38"
    },
    {
        "remaining": 35.12,
        "timestamp": "2024-09-10 01:41:34"
    },
    {
        "remaining": 35.14,
        "timestamp": "2024-09-10 01:40:31"
    },
    {
        "remaining": 35.15,
        "timestamp": "2024-09-10 01:39:26"
    },
    {
        "remaining": 35.17,
        "timestamp": "2024-09-10 01:38:21"
    },
    {
        "remaining": 35.19,
        "timestamp": "2024-09-10 01:37:18"
    },
    {
        "remaining": 35.21,
        "timestamp": "2024-09-10 01:36:13"
    },
    {
        "remaining": 35.22,
        "timestamp": "2024-09-10 01:35:10"
    },
    {
        "remaining": 35.22,
        "timestamp": "2024-09-10 01:34:05"
    },
    {
        "remaining": 35.26,
        "timestamp": "2024-09-10 01:31:29"
    },
    {
        "remaining": 35.28,
        "timestamp": "2024-09-10 01:30:24"
    },
    {
        "remaining": 35.3,
        "timestamp": "2024-09-10 01:29:21"
    },
    {
        "remaining": 35.31,
        "timestamp": "2024-09-10 01:28:26"
    },
    {
        "remaining": 35.33,
        "timestamp": "2024-09-10 01:27:24"
    },
    {
        "remaining": 35.35,
        "timestamp": "2024-09-10 01:26:19"
    },
    {
        "remaining": 35.37,
        "timestamp": "2024-09-10 01:25:13"
    },
    {
        "remaining": 35.38,
        "timestamp": "2024-09-10 01:24:09"
    },
    {
        "remaining": 35.39,
        "timestamp": "2024-09-10 01:23:03"
    },
    {
        "remaining": 35.41,
        "timestamp": "2024-09-10 01:21:58"
    },
    {
        "remaining": 35.43,
        "timestamp": "2024-09-10 01:20:53"
    },
    {
        "remaining": 35.47,
        "timestamp": "2024-09-10 01:19:06"
    },
    {
        "remaining": 35.49,
        "timestamp": "2024-09-10 01:18:01"
    }
]

修正要点

  1. 使用箭头函数在 setInterval 中绑定正确的 this 上下文

    • 使用 setInterval(() => { this.fetchData(); }, 60000),确保 fetchData 在每次调用时使用正确的组件上下文,避免函数指针错误。
  2. 防止重复创建图表

    • 检查 this.chart 是否已存在,只有在首次创建时调用 updateChart,在后续更新中只调用 this.chart.update(),防止不断创建新图表导致的栈溢出。
  3. 优化 fetchData 的数据处理逻辑

    • 确保每次数据更新只更新已有图表,不会触发多余的重绘或递归调用。

通过以上优化,可以避免无限递归和重复调用引发的 Maximum call stack size exceeded 错误。

相关推荐
liangshanbo12152 小时前
在React中构建自己的自定义Hooks:获取数据的简单指南
前端·react.js·前端框架
抖码2 小时前
【VUE】Vue的diff算法和React的diff算法
javascript·vue.js·react.js
【D'accumulation】2 小时前
JavaScript的生成器与组合学习
开发语言·前端·javascript·学习
Li_Ning212 小时前
【react】开发常用hooks统计
前端·javascript·react.js
GISer_Jing2 小时前
React事件机制详解
前端·javascript·面试
IT农民工~5 小时前
《网络基础之 HTTP 协议:常见 HTTP 方法详解》
服务器·前端·网络·网络协议·http·html5
Dovir多多6 小时前
渗透测试入门学习——使用python脚本自动跟踪csrf_token实现对网站登录界面的暴力破解
前端·python·安全·web安全·网络安全·php·csrf
余生H6 小时前
前端的全栈混合之路Meteor篇:分布式数据协议DDP深度剖析
前端·javascript·分布式·rpc·全栈·meteor
l1x1n06 小时前
No.15 笔记 | CSRF 跨站请求伪造
前端·笔记·csrf
..undefined6 小时前
package.json配置
前端·json