1.交互逻辑:
- 点击页面的“提交”button,向后台发送数据处理请求;
- 后台处理数据;
- 前端根据后台的处理进度实时更新进度条。
个人愚见:能在前端估计出进度的尽量在前端做伪实时的进度条(像发送文件那种),这才是上策;实在没法估计后台计算时间,又实在是等的久的让人难熬的才这么干,这是下下策。
2. 功能实现:
2.1 前端
2.1.1 HTML
- Html页面用boostrap的进度条, 进度条由2个div嵌套而成,修改内层div的width可以更新进度,外层div (id=”prog_out”) , 内层div (id=”prog_in”);
- 给button绑定一个onclick方法”submit_query()”。
<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>
2.1.2 javascript
- 在onclick方法中设置一个setInterval函数,用于持续请求后台进度,不断更新进度条;
- 向后台发送数据处理请求,当该请求成功返回后结束setInterval函数,并更改进度条样式。
- 由于setInterval和getJSON的回调函数都是异步执行,这里就相当于做了个登记,将任务加入队列。因此submit_query不必等待他俩就可以顺利结束。
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, 改为完成形态
});
}
2.2 后端
我这里使用的后端为Django, 使用别的后端思路相当。
2.2.1. 设置两个url, 一个指向处理数据的的函数,另一个指向请求进度的函数
urls.py
url(r'^thisiurl$', views.process_data, name='process'), # 处理数据的url, 当前页面的地址
url(r'^progressurl$', views.show_progress, name='progress'), # 查询进度的url, 不需要html页面
# thisiurl和progressurl用自己的url
views.py
2.2.2. 用全局变量记录处理进度,process_data函数负责具体任务,同时更新后台进度值,show_progress负责将当前进度值返回给前端。当全局变量不被识别的时候使用global关键字。
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)
3. 实现效果
未完成形态
完成形态