前端实时更新后端处理进度

交互逻辑

  1. 点击页面的“提交”button,向后台发送数据处理请求;
  2. 后台处理数据;
  3. 前端根据后台的处理进度实时更新进度条。

个人愚见:能在前端估计出进度的尽量在前端做伪实时的进度条(像发送文件那种),这才是上策;实在没法估计后台计算时间,又实在是等的久的让人难熬的才这么干,这是下下策。


功能实现

前端

HTML

  1. Html页面用boostrap的进度条, 进度条由2个div嵌套而成,修改内层div的width可以更新进度,外层div (id=”prog_out”) , 内层div (id=”prog_in”);
  2. 给button绑定一个onclick方法”submit_query()”。
    1
    2
    3
    4
    5
    6
    <div id="prog_out" class="progress progress-striped active">
    <div id="prog_in" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
    </div>
    </div>
    <button type="button" class="btn btn-default" onclick="submit_query()">提交</button>

javascript

  1. 在onclick方法中设置一个setInterval函数,用于持续请求后台进度,不断更新进度条;
  2. 向后台发送数据处理请求,当该请求成功返回后结束setInterval函数,并更改进度条样式。
  3. 由于setInterval和getJSON的回调函数都是异步执行,这里就相当于做了个登记,将任务加入队列。因此submit_query不必等待他俩就可以顺利结束。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function submit_query(btn){
    var sitv = setInterval(function(){
    var prog_url = ... // prog_url指请求进度的url,后面会在django中设置
    $.getJSON(prog_url, function(res){
    $('#prog_in').width(res + '%'); // 改变进度条进度,注意这里是内层的div, res是后台返回的进度
    });
    }, 1000); // 每1秒查询一次后台进度
    var this_url = ... // 指当前页面的url
    var yourjson = ...
    $.getJSON(thisurl, yourjson, function(res){
    // ...
    clearInterval(sitv); // 此时请求成功返回结果了,结束对后台进度的查询
    $('#prog_out').attr("class", "progress progress-bar-success"); // 修改进度条外层div的class, 改为完成形态
    });
    }

后端

我这里使用的后端为Django, 使用别的后端思路相当。
2.2.1. 设置两个url, 一个指向处理数据的的函数,另一个指向请求进度的函数

urls.py

1
2
3
url(r'^thisiurl$', views.process_data, name='process'), # 处理数据的url, 当前页面的地址
url(r'^progressurl$', views.show_progress, name='progress'), # 查询进度的url, 不需要html页面
# thisiurl和progressurl用自己的url

views.py

用全局变量记录处理进度,process_data函数负责具体任务,同时更新后台进度值,show_progress负责将当前进度值返回给前端。当全局变量不被识别的时候使用global关键字。

1
2
3
4
5
6
7
8
9
10
11
num_progress = 0 # 当前的后台进度值(不喜欢全局变量也可以很轻易地换成别的方法代替)
def process_data(request):
# ...
for i in range(12345):
# ... 数据处理业务
num_progress = i * 100 / 12345; # 更新后台进度值,因为想返回百分数所以乘100
return JsonResponse(res, safe=False)
def show_progress(request):
return JsonResponse(num_progress, safe=False)


实现效果

未完成形态
这里写图片描述

完成形态
这里写图片描述