关于util倒计时的实现问题。

讨论 已结 2 1136
岁月小偷
悬赏:20飞吻
目前util提供的countdawn咋一看很高大上,看了里面的执行逻辑这行后背一凉,这能走得准么?很无聊的观察了好一会,确实是一闪一闪的一秒一秒的倒数,但是,这个时间周期的真是一秒吗?好吧代码才是最为关键的,感觉是不那么靠谱的。
源码util对countdown的实现
//倒计时
,countdown: function(endTime, serverTime, callback){
var that = this
,type = typeof serverTime === 'function'
,end = new Date(endTime).getTime()
,now = new Date((!serverTime || type) ? new Date().getTime() : serverTime).getTime()
,count = end - now
,time = [
Math.floor(count/(1000*60*60*24)) //天
,Math.floor(count/(1000*60*60)) % 24 //时
,Math.floor(count/(1000*60)) % 60 //分
,Math.floor(count/1000) % 60 //秒
];

if(type) callback = serverTime;

var timer = setTimeout(function(){
that.countdown(endTime, now + 1000, callback);
}, 1000);

callback && callback(count > 0 ? time : [0,0,0,0], serverTime, timer);

if(count <= 0) clearTimeout(timer);
return timer;
}
那么问题来了,到setTimeout之前的代码执行都不需要时间么?特别是浏览器压力上来之后,就显示一个走得慢的机械表,至于能慢多少,就看你让它倒数多久还有浏览器的压力多大了。
自己重构了一下这个方法,不用修改源码,可以利用use util再对util扩展出新的方法。代码如下有兴趣的可以看看试一试。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="layui-src/css/layui.css" media="all">
<link rel="stylesheet" href="jstree/dist/themes/default/style.css" media="all">
<!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
</head>
<body>
<table id="testTable"></table>

<script src="layui-src/layui.js" charset="utf-8"></script>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->

<script>
layui.use(['jquery', 'table', 'layer', 'laydate', 'util'], function ($, table, layer, laydate, util) {
util.getCountDown = function (endTime, serverTime) {
var that = this
, end = new Date(endTime).getTime()
, now = new Date(serverTime ? serverTime : new Date().getTime()).getTime()
, count = end - now;
if (count <= 0) {
return;
}
return [
Math.floor(count / (1000 * 60 * 60 * 24)) //天
, Math.floor(count / (1000 * 60 * 60)) % 24 //时
, Math.floor(count / (1000 * 60)) % 60 //分
, Math.floor(count / 1000) % 60 //秒
];
};
util.countdownPrecise = function (endTime, serverTime, callback) {
var that = this
, type = typeof serverTime === 'function'
, now = new Date((!serverTime || type) ? new Date().getTime() : serverTime).getTime();
if (type) callback = serverTime;
if (!callback) {
return;
}
// 第一次显示
var time = that.getCountDown(endTime, now);
callback(time ? time : [0, 0, 0, 0], serverTime);
var timer = setInterval(function () {
var time = that.getCountDown(endTime, now += 1000);
callback(time ? time : [0, 0, 0, 0], serverTime);
time || clearInterval(timer);
}, 1000);

return timer;
};
//执行一个laydate实例
var tableObj = table.render({
id: 'testTable',
elem: '#testTable',
width: 660,
height: 480,
data: [
{id: 1, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 2, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 3, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 4, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 5, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 6, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 7, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 8, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 9, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 10, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 11, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'},
{id: 12, countDown: '2018/04/26 22:00:00', countDown2: '2018/04/26 22:00:00'}
],
page: {},
cols: [[
{type: 'checkbox', fixed: true},
{field: 'id', width: 80, title: 'ID', fixed: true},
{
field: 'countDown', title: '框架倒计时(到2018/04/26 22:00:00)', templet: function (d) {
return '<div class="countDown" data-date="' + (d.countDown || '') + '"></div>';
}
},
{
field: 'countDown2', title: '重构倒计时(2018/04/26 22:00:00)', templet: function (d) {
return '<div class="countdownPrecise" data-date="' + (d.countDown || '') + '"></div>';
}
},

]],
done: function (res, curr, count) {
var elem = this.elem.next();
var bodyElem = elem.find('.layui-table-main');
layui.each(bodyElem.find('.countDown'), function (index, domElem) {
domElem = $(domElem);
if (!domElem.data('date')) {
return;
}
var endTime = new Date(domElem.data('date')).getTime();
// serverTime = new Date().getTime();
util.countdown(endTime, null, function (date, serverTime, timer) {
var str = date[0] + '天' + date[1] + '时' + date[2] + '分' + date[3] + '秒';
domElem.html(str);
});
});
layui.each(bodyElem.find('.countdownPrecise'), function (index, domElem) {
domElem = $(domElem);
if (!domElem.data('date')) {
return;
}
var endTime = new Date(domElem.data('date')).getTime();
// serverTime = new Date().getTime();
util.countdownPrecise(endTime, null, function (date, serverTime, timer) {
var str = date[0] + '天' + date[1] + '时' + date[2] + '分' + date[3] + '秒';
domElem.html(str);
});
});
}
});
});
</script>
</body>
</html>
执行了一段时间加上对浏览器稍微蹂躏下的结果如下图

最后有个比较哲学的问题:倒数真的需要传serverTime吗?想不出什么应用场景。请教一下大家看看有木有什么例子之类的,如果真的不需要的话代码还可以更加简洁高效。
回帖
  • 你的最后一个问题,其实没有哲学的问题,而是必须用到serverTime,不然会有歧义,因为客户端的时间对于系统来说,不可控。
    比如:会员查看自己的会员到期时间,查询的是客户端时间……可想而知问题了……
    0 回复
  • @藕酥鱼胖胖 get it.学到了[赞]
    0 回复