Google Apps Script多图表加载慢且偶失败的优化方案咨询
多图表Web应用加载优化方案
针对你遇到的加载慢、偶发图表失败问题,从减少服务器请求、优化数据处理、简化前端逻辑三个核心方向给出优化方案:
一、合并Google Charts初始化,避免重复加载与回调冲突
原代码两次调用google.charts.load,且绑定多个setOnLoadCallback,容易导致加载顺序混乱。改成一次性加载所有需要的图表包,仅绑定一个初始化回调:
document.addEventListener('DOMContentLoaded', function() { // 保留原有参数获取逻辑 const name = document.getElementById("athletename").textContent; // 一次性加载所有依赖的图表包 google.charts.load('current', { packages: ['corechart', 'line', 'scatter'] }); // 统一触发数据请求与图表绘制流程 google.charts.setOnLoadCallback(() => { google.script.run .withSuccessHandler(drawAllCharts) .withFailureHandler((error) => { console.error('数据请求失败:', error); // 可添加用户可见的错误提示 }) .getAllChartsData(name, sDay_load, eDay_load); }); // 通用图表绘制函数,消除冗余代码 function createAndDrawChart(containerId, dataRows, columns, chartType, options = {}) { const data = new google.visualization.DataTable(); columns.forEach(col => data.addColumn(col.type, col.label)); data.addRows(dataRows); let chart; switch(chartType) { case 'scatter': chart = new google.visualization.ScatterChart(document.getElementById(containerId)); chart.draw(data, google.charts.Scatter.convertOptions(options)); break; default: chart = new google.visualization.LineChart(document.getElementById(containerId)); chart.draw(data, options); } } // 统一处理所有数据并批量绘制图表 function drawAllCharts(allData) { // 体重图表(请根据实际列配置调整columns参数) createAndDrawChart('Weight_chart_div', allData.weight, [{type: 'date', label: '日期'}, {type: 'number', label: '体重'}], 'line', {title: '体重变化'}); // 睡眠图表 createAndDrawChart('Sleep_chart_div', allData.sleep, [{type: 'date', label: '日期'}, {type: 'number', label: '睡眠时长'}], 'line', {title: '睡眠时长'}); // 心率图表 createAndDrawChart('HeartRate_chart_div', allData.heartRate, [{type: 'date', label: '日期'}, {type: 'number', label: '心率'}], 'line', {title: '心率变化'}); // 血氧饱和度图表 createAndDrawChart('OxygenSaturation_chart_div', allData.oxygenSaturation, [{type: 'date', label: '日期'}, {type: 'number', label: '血氧饱和度'}], 'line', {title: '血氧饱和度'}); // 体温图表 createAndDrawChart('BodyTemperature_chart_div', allData.bodyTemperature, [{type: 'date', label: '日期'}, {type: 'number', label: '体温'}], 'line', {title: '体温变化'}); // 早晨状态图表 createAndDrawChart('Morning_chart_div', allData.morning, [{type: 'date', label: '日期'}, {type: 'number', label: '睡眠质量'}, {type: 'number', label: '疲劳度'}, {type: 'number', label: '食欲'}], 'line', {title: '早晨状态'}); // 夜晚状态图表 createAndDrawChart('Night_chart_div', allData.night, [{type: 'date', label: '日期'}, {type: 'number', label: '睡眠准备'}, {type: 'number', label: '入睡难度'}], 'line', {title: '夜晚状态'}); // 早晨症状散点图 createAndDrawChart('Morning_symptoms', allData.morningSymptoms, [{type: 'date', label: '日期'}, {type: 'number', label: '症状指数'}], 'scatter', {title: '早晨症状'}); // 夜晚症状散点图 createAndDrawChart('Night_symptoms', allData.nightSymptoms, [{type: 'date', label: '日期'}, {type: 'number', label: '症状指数'}], 'scatter', {title: '夜晚症状'}); } });
二、合并服务器端数据请求,优化数据处理逻辑
原代码每个图表单独发起一次服务器请求(共9次),且依赖临时工作表处理数据,耗时极高。改成一次性返回所有图表数据,直接在服务器端完成筛选:
// Google Apps Script 端代码 function getAllChartsData(targetName, startDay, endDay) { const wb = SpreadsheetApp.getActiveSpreadsheet(); const dbSheet = wb.getSheetByName(DBSHEETNAME); const allData = dbSheet.getDataRange().getValues(); const header = allData[0]; const rows = allData.slice(1); // 直接筛选符合日期范围与用户名的数据 const filteredRows = rows.filter(row => { const rowDate = row[0]; const rowName = row[1]; return rowDate >= new Date(startDay) && rowDate <= new Date(endDay) && rowName === targetName; }); // 定义各图表需要的列索引(请根据实际表头调整) const columnMap = { weight: [0, 2], // 日期列、体重列 sleep: [0, 3], // 日期列、睡眠时长列 heartRate: [0, 4], // 日期列、心率列 oxygenSaturation: [0, 5], // 日期列、血氧列 bodyTemperature: [0, 6], // 日期列、体温列 morning: [0, 7, 8, 9], // 日期列、睡眠质量、疲劳度、食欲 night: [0, 10, 11], // 日期列、睡眠准备、入睡难度 morningSymptoms: [0, 12], // 日期列、早晨症状指数 nightSymptoms: [0, 13] // 日期列、夜晚症状指数 }; // 整理各图表所需数据 const result = {}; Object.keys(columnMap).forEach(key => { result[key] = filteredRows.map(row => { return columnMap[key].map(index => row[index]); }); }); return result; }
三、额外优化建议
- 添加加载状态:在数据请求和绘制过程中显示加载动画,提升用户体验;
- 图表懒加载:监听滚动事件,仅绘制进入视口的图表,减少初始渲染压力;
- 数据缓存:使用
CacheService缓存同一用户、同一日期范围的请求结果,避免重复计算; - 失败重试:给服务器请求添加重试逻辑,处理偶发的请求失败问题。
内容的提问来源于stack exchange,提问作者Cathy Cathy
相关产品推荐
相关产品推荐

