利用Ajax提升网页渲染速度——以Highcharts为例

先来看看速度优化对比(这里用了 DjangoDebugToolbar库来查看状态)

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。 AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

在项目一开始时, 为了呈现数据的工资趋势图, 把所有的关键词趋势数据一次性处理后发送至前端, 造成DOM数目过多, 导致网页渲染数据极慢, 到了无法忍受的1分多钟的时间.

后面使用Ajax的 get方法, 只对于要下钻的关键词工资趋势获取对应数据, 最终把时间压到了20秒以内(由于整个页面还包含其他图表, 如果只有单个图表, 时间可以进一步缩短)

前端发送请求

下面的代码片就是添加了 get方法后的highcharts片段.

这段代码的意思是用 get函数发送请求, 请求的内容是 {'keyword':String(e.point.name),'city':'东莞'}

url/get_trend_by_word/, 这里的url会交由Django后台的路由识别出对应函数进行处理.

处理后的返回数据保存在 ret中. 函数体内部把返回的数据 ret保存在 series中供后面的图表渲染.

# 若显示不全,请滑动屏幕
 $.get('/get_trend_by_word/', {'keyword':String(e.point.name), 'city': '东莞'}, function(ret){           
              series = ret
            });

Django响应请求

在Django的视图模块 views.py中, 响应ajax请求, 处理完毕后发送回前端

# 若显示不全,请滑动屏幕
def get_trend_by_word(request):
    ...

    #把request中的变量值提取出来, 用于处理
    keyword = request.GET['keyword']
    city = request.GET['city']

    ...
    return JsonResponse(salary_trend, safe=False)

参考资料

关于HighCharts的Ajax例子可以参考官方文档 https://www.hcharts.cn/docs/ajax

菜鸟教程 http://www.runoob.com/ajax/ajax-tutorial.html

还在修改中的项目, 欢迎吐槽(逃

https://github.com/FesonX/JobDataViewer

代码对比

(觉得太丑可以直接跳过)

下面这段是修改前的js代码片

# 若显示不全,请滑动屏幕
    var drilldown = {
        series: [
            {% for k, v in series1.items %}
                {
                type: 'line',
                id: '{{ k }}',
                name: '{{ k }}',
                data: [
                    {% for i in v %}
                        {% for j in i %}
                            {% if forloop.first %} ['{{ j | date:"Y-m-d" }}', {% endif %}
                            {% if forloop.last %} {{ j }}], {% endif %}
                        {% endfor %}
                    {% endfor %}
                ]
                },
            {% endfor %}
            ]};

下面这段是修改后的js代码片

# 若显示不全,请滑动屏幕
  $(function (){
    $('#trend').highcharts({
      chart: {
        type: 'column',
        events:{
          drillup: function(e) {
              // 上钻回调事件
              console.log(e.seriesOptions);
            },
          drilldown: function (e) {
           // 重点在这一句
            $.get('/get_trend_by_word/', {'keyword':String(e.point.name), 'city': '东莞'}, function(ret){
              console.log(ret.Animals)
              series = ret
              console.log(series)
            });
          if (!e.seriesOptions) {
            var chart = this,
            drilldowns = {
              type:'line',
            },
          series = drilldowns;
          // Show the loading label
          chart.showLoading('正在获取数据...');
          setTimeout(function () {
            chart.hideLoading();
            chart.addSeriesAsDrilldown(e.point, series);
          }, 1000);
          }
          }
        }
        },

     ...

    });
  });

下面这段是修改前的python代码片

# 若显示不全,请滑动屏幕
def dataViewer(request):
    ...

    # 使用一个循环将所有关键词的工资趋势一次性保存在一个字典里
    trends_dict = {kd: get_salary_trend(job_info, kd, city) 
            for kd in top_keyword if (get_salary_trend(job_info, kd, city).empty) is False}

    ...

    # 把该工资趋势所有数据一次性发送到前端渲染
    context = {
        'cities': items[:20],
        'series': series.sort_values()[::-1][:25],
        'keyword_dict': kd_salary,
        'top_job_counts':job_count_rank.sort_values()[::-1][:25],
        # 按索引排序
        'trends_dict': Series(trends_dict).sort_index()[::-1][:25],
        'city':city, 
    }
    return render(request, 'data_viewer.html', context)

def get_salary_trend(job_info, keyword, city):
    # 获取工资趋势
    if(city != '全国' or city != '异地招聘'):
        pattern = r'^(' + city + '|' + city + ')'
        # items = JobField.objects(__raw__={'key_word':keyword, 'job_city': city})
        items = JobField.objects(Q(key_word=keyword) & Q(job_city=city))
    else:
        # items = JobField.objects(__raw__={'key_word':keyword})
        items = JobField.objects(key_word=keyword)

    salary_trend_list = []

    dates = items.distinct("create_time")
    for day in dates:

        item = items(__raw__={'create_time': day})
        salary_avg = item.average('salary_avg')
        salary_trend = [day, round(salary_avg, 2)]
        salary_trend_list.append(salary_trend)

    salary_trend = dict(salary_trend_list)
    salary_trend = Series(salary_trend)

    return salary_trend

下面这段是修改后的python代码片

# 若显示不全,请滑动屏幕
# 根据网页请求的关键词, 把对应关键词的工资趋势数据保存下来, 发送到前端
def get_trend_by_word(request):
    # use Ajax to reduce dom
    keyword = request.GET['keyword']
    city = request.GET['city']

    keyword = str(keyword)
    city = str(city)

    # 获取工资趋势
    if(city != '全国' or city != '异地招聘'):
        pattern = r'^(' + city + '|' + city + ')'
        items = JobField.objects(Q(key_word=keyword) & Q(job_city=city))
    else:
        items = JobField.objects(key_word=keyword)

    salary_trend_list = []

    dates = items.distinct("create_time")
    for day in dates:
        item = items(__raw__={'create_time': day})
        salary_avg = item.average('salary_avg')
        salary_trend = [str(day)[0:10], round(salary_avg, 2)]
        salary_trend_list.append(salary_trend)
    salary_trend_list = Series(salary_trend_list).sort_index()[::-1]

    salary_trend = {'type': 'line', 'name': keyword, 'data':[i for i in salary_trend_list]}

    return JsonResponse(salary_trend, safe=False)

入门小白, 欢迎大家指出错误, 技术交流

今日作者: 光光同学_

不爱看电影的摄影师不是好的程序员

原文发布于微信公众号 - 程序员的碎碎念(gh_53e607dd4782)

原文发表时间:2018-05-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏令仔很忙

Web前端----Javascript模块化

一提到模块化,也许我们首先想到的是做项目的时候进行模块设计,按照功能划分不同的模块,最后通过模块的选择和组合组成最终的产品;那把模块化的思想放到前端页面,js...

22310
来自专栏coding for love

在线商城项目06-商品列表页前端逻辑实现

step1:价格过滤列表的字段显示。 这里,我们不做太复杂的逻辑,这些过滤字段不从后端请求,也不由用户输入,而是在前端写死。在GoodsList.vue中进行...

14510
来自专栏iOS技术

iOS 多个scrollview联动(附DEMO)

在移动应用实际开发过程中,往往会有多个scrollview嵌套的界面需求,这种需求已经司空见惯,解决方案也多种多样,这里就介绍一下我认为最优的解决方案。

39470
来自专栏逸鹏说道

模仿百度新闻列表底部的“加载更多”

前言   自从上个月来到了学校的信息化中心实习后自由安排的时间越来越少,遂好久没来更新博客了。   昨天在完成一个模仿手机端百度新闻列表底“点击加载更多”的功能...

36380
来自专栏闻道于事

商城项目回顾整理(一)前台页面布局

登录页面: 1 <%@ page language="java" contentType="text/html; charset=utf-8" 2 ...

44430
来自专栏代码GG之家

Android 关机对话框概率没有阴影故障分析

Android 关机对话框概率没有阴影故障分析 ? 以玩的心态,做着感兴趣的事情而已,别无其他杂念。 android recent key长按事件弹起触发最近列...

25360
来自专栏知晓程序

开发 | 技术高人如何开发小程序?他们用这套方法

11620
来自专栏逸鹏说道

TypeScript 1.6发布:完全支持React/JSX

2012年,微软推出了一个能够在Node.js上运行的开源语言——TypeScript。作为JavaScript的超集,TypeScript在兼容JavaScr...

28550
来自专栏前端架构与工程

《微信小程序七日谈》- 第一天:人生若只如初见

《微信小程序七日谈》系列文章: 本系列的文章并非初学教程,而是笔者在具体开发过程中遇到的问题以及部分解决方案。 微信小程序自公布以来就被捧上了天,新闻一波接一...

23680
来自专栏Debian社区

Debian 环境下有趣的命令

安装  $ sudo apt-get install sl 运行  $ /usr/games/sl

25750

扫码关注云+社区

领取腾讯云代金券