首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >答复的CR员额百分比随时间变化的图表.第2部分

答复的CR员额百分比随时间变化的图表.第2部分
EN

Code Review用户
提问于 2018-12-13 01:24:30
回答 1查看 71关注 0票数 3

我创建了一个图表来显示问题回答率随时间的变化。第一个版本使用PHP从聊天记录中获取数据。我为我的网络空间注册的子域不支持HTTPS,因此当在那里运行时,对file_get_contents()的调用将失败。正因为如此,我开始研究其他的选择。

我查看了使用其他脚本语言,发现Github提供了Github页面,并指出它是安全的,但不允许任何服务器端脚本。因此尝试将客户端JavaScript与fetchAPI接口结合使用。最初存在CORS问题,经过一些研究,我发现了这个职位,它提到了一个充当代理的Heroku页面。我使用代理来获取数据,我对新的ES-8 异步函数await操作符很感兴趣,所以我使用了这些数据。

代码看上去怎么样?你会改变什么?

你能通过提供一个好的答案来帮助图表结果上升吗?而且--记住对任何有帮助的答案进行投票。

代码语言:javascript
复制
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);
};
代码语言:javascript
复制
h1 {
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}
代码语言:javascript
复制
<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>
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-12-13 21:15:21

一个错误和一个逻辑问题.

如果您将代码作为模块运行或以严格模式运行,由于未定义变量,代码将失败。解析HTML时也有一个问题,如果缺少数据,时间戳和百分比就会不同步,因为您不能增加i

异步函数通过将错误分配给返回的允诺catch回调来处理错误。您已经将一个try catch封装在可能抛出不相关的开发错误的代码上,您将其看作是“错误加载数据”,而不是将合法错误与源/逻辑错误区分开来。

当获取的数据是坏的(例如404页)时,还不清楚您打算发生什么,这不会抛出错误,并且您忽略这些错误而不提供任何反馈。

更清晰地将角色与提取和解析分离为函数,而不是单个异步函数。

数据也到处都是,图设置在顶部声明,然后在创建图形的函数中声明更多数据。

通用点

  • contentElement中使用未声明的变量getGraphData
  • 为什么if (matches.length) {会发生这种事?如果是这样的话,这不意味着i作为timeStamps索引不再匹配for循环位置了吗?
  • window是默认对象,不需要直接引用。如果要定义全局值,请在全局范围内清楚地定义它们。如果它们是外部的,则使用注释来指示它们是外部全局的。
  • 为什么给一个从未使用过的变量赋值?window.myLine = new Chart(
  • 保持干燥。轴对象可以是一个函数,也可以用函数约简其他几个部分。
  • 通过避免单一用途变量声明,减少源代码行数。
  • 尽可能避免使用innerHTML,因为它比textContent慢得多。
  • 在控制内容时使用直接元素id引用。
  • 只将相关代码包装在try中。ECMAScript 2018允许您在捕获令牌之后删除错误对象。更好的是,将函数的异步部分分开,并使用允诺catch函数。
  • 尽可能使用最短的表格。你用的是datasets: [Object.assign(dataset, {data})],可以是datasets: [{...dataset, data}]
  • 为什么if (contents.length === timestamps.length)和没有警告如果数据是坏的?
  • 双线/同一行打开[{({[[.等等,后面应该是单缩和匹配的双关闭。见重写。
  • 冗余重复的X轴标签内容" 12:00 AM"可以删除
  • 图形标题和页面标题是不同的。也许可以从页面标题分配图表标题?

可能重写

这种重写减少了行数,并将大多数需求封装在一个函数中,从而减少了全局命名空间污染。

数据审查是有点不清楚,所以只是添加到图形功能,以显示警告,如果没有发现数据。

代码语言:javascript
复制
"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???");
        }
    }    
}
代码语言:javascript
复制
body {
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}
h2 {
  text-align : center;
}
#errorEl { 
  display : none;
  color: red;
}
代码语言:javascript
复制
<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>
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/209576

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档