我创建了一个图表来显示问题回答率随时间的变化。第一个版本使用PHP从聊天记录中获取数据。我为我的网络空间注册的子域不支持HTTPS,因此当在那里运行时,对file_get_contents()的调用将失败。正因为如此,我开始研究其他的选择。
我查看了使用其他脚本语言,发现Github提供了Github页面,并指出它是安全的,但不允许任何服务器端脚本。因此尝试将客户端JavaScript与fetchAPI接口结合使用。最初存在CORS问题,经过一些研究,我发现了这个职位,它提到了一个充当代理的Heroku页面。我使用代理来获取数据,我对新的ES-8 异步函数和await操作符很感兴趣,所以我使用了这些数据。
代码看上去怎么样?你会改变什么?
你能通过提供一个好的答案来帮助图表结果上升吗?而且--记住对任何有帮助的答案进行投票。
const url = 'https://chat.stackexchange.com/search?q=%22RELOAD!+There+are%22&user=125580&room=8595&pagesize=150';
const pUrl = 'https://cors-escape.herokuapp.com/' + url;
const chartOptions = {
title: {
display: true,
text: 'Answered percentage in recent months'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Date'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Percentage'
}
}]
}
};
const dataset = {
label: 'Answered Percentage',
backgroundColor: window.chartColors.red,
borderColor: window.chartColors.red,
fill: false
};
async function getGraphData() {
const loadingImage = document.getElementById('loading');
try {
const response = await fetch(pUrl);
const container = document.createElement('div');
container.innerHTML = await response.text();
const timestamps = container.getElementsByClassName('timestamp');
const contents = container.getElementsByClassName('content');
const labels = [],
data = [];
if (contents.length === timestamps.length) {
let i = 0;
for (contentElement of contents) {
const matches = contentElement.innerHTML.match(/\d{2}.\d{4}/);
if (matches.length) {
data.unshift(matches[0]);
labels.unshift(timestamps[i++].innerHTML);
}
}
if (data.length) {
loadingImage.style.display = 'none';
drawChart(data, labels);
}
}
} catch (err) {
loadingImage.parentNode.innerHTML = 'Error loading data';
}
}
document.addEventListener('DOMContentLoaded', getGraphData)
const drawChart = (data, labels) => {
Chart.defaults.global.legend.display = false;
const config = {
type: 'line',
data: {
labels,
datasets: [Object.assign(dataset, {data})]
},
options: chartOptions
};
const ctx = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx, config);
};h1 {
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}<script src="//www.chartjs.org/dist/2.7.2/Chart.bundle.js"></script>
<script src="//www.chartjs.org/samples/latest/utils.js"></script>
<h1>
Graph of Answered Question Percentage on Code Review SE
</h1>
<div style="width:75%;">
<canvas id="canvas"></canvas>
<img src="https://loading.io/spinners/bars/index.progress-bar-facebook-loader.gif" id="loading" />
</div>发布于 2018-12-13 21:15:21
如果您将代码作为模块运行或以严格模式运行,由于未定义变量,代码将失败。解析HTML时也有一个问题,如果缺少数据,时间戳和百分比就会不同步,因为您不能增加i。
异步函数通过将错误分配给返回的允诺catch回调来处理错误。您已经将一个try catch封装在可能抛出不相关的开发错误的代码上,您将其看作是“错误加载数据”,而不是将合法错误与源/逻辑错误区分开来。
当获取的数据是坏的(例如404页)时,还不清楚您打算发生什么,这不会抛出错误,并且您忽略这些错误而不提供任何反馈。
更清晰地将角色与提取和解析分离为函数,而不是单个异步函数。
数据也到处都是,图设置在顶部声明,然后在创建图形的函数中声明更多数据。
contentElement中使用未声明的变量getGraphDataif (matches.length) {会发生这种事?如果是这样的话,这不意味着i作为timeStamps索引不再匹配for循环位置了吗?window是默认对象,不需要直接引用。如果要定义全局值,请在全局范围内清楚地定义它们。如果它们是外部的,则使用注释来指示它们是外部全局的。window.myLine = new Chart(innerHTML,因为它比textContent慢得多。datasets: [Object.assign(dataset, {data})],可以是datasets: [{...dataset, data}]if (contents.length === timestamps.length)和没有警告如果数据是坏的?[{,({或[[.等等,后面应该是单缩和匹配的双关闭。见重写。" 12:00 AM"可以删除这种重写减少了行数,并将大多数需求封装在一个函数中,从而减少了全局命名空间污染。
数据审查是有点不清楚,所以只是添加到图形功能,以显示警告,如果没有发现数据。
"use strict";
// uses chartColors defined in ???.js
document.addEventListener("DOMContentLoaded", displayAnswerRate);
function displayAnswerRate() {
const CORS_PROXY = "https://cors-escape.herokuapp.com/";
const url = "https://chat.stackexchange.com/search?q=%22RELOAD!+There+are%22&user=125580&room=8595&pagesize=150";
const showError = message => {
errorEl.style.display = "block";
errorEl.textContent = message;
}
getDataURL(url)
.then(parseDataAndChart)
.catch(() => {
loading.style.display = "none";
showError("Error loading data");
});
async function getDataURL(url) { return (await fetch(CORS_PROXY + url)).text() }
function parseDataAndChart(markup){
const elsByClass = cName => [...html.querySelectorAll("." + cName)].reverse();
const html = document.createElement('div');
html.innerHTML = markup;
drawChart(
elsByClass("content").map(el => el.textContent.split("(")[1].split("%")[0]),
elsByClass("timestamp").map(el => el.textContent.replace(" 12:00 AM",""))
);
loading.style.display = "none";
}
function drawChart(data, labels) {
const axis = name => [{display: true, scaleLabel: {display: true, labelString: name}}];
if (data.length > 0) {
Chart.defaults.global.legend.display = false;
new Chart(canvas.getContext('2d'), {
type: 'line',
data: {
labels,
datasets: [{
label: 'Answered Percentage',
backgroundColor: chartColors.red,
borderColor: chartColors.red,
data,
fill: false
}]
},
options: {
title: {display: true, text: heading.textContent},
scales: { xAxes: axis("Date"), yAxes: axis("Percentage") }
}
});
} else {
showError("No data found???");
}
}
}body {
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}
h2 {
text-align : center;
}
#errorEl {
display : none;
color: red;
}<script src="//www.chartjs.org/dist/2.7.2/Chart.bundle.js"></script>
<script src="//www.chartjs.org/samples/latest/utils.js"></script>
<div style="width:75%;">
<h2 id="heading">Answered percentage in recent months</h2>
<div id="errorEl"></div>
<canvas id="canvas"></canvas>
<img src="https://loading.io/spinners/bars/index.progress-bar-facebook-loader.gif" id="loading" />
</div>https://codereview.stackexchange.com/questions/209576
复制相似问题