服务端时间不须要屡次请求:其由客户端与服务端的时间差,和当前的客户端时间比对得出;从而减小了服务端时间的请求次数,提高性能;且防止了浏览器切换,程序挂起时,倒计时的失真;serverTime = frontTime - gaphtml
客户端时间校准:增长了时间校准,防止用户在倒计时阶段修改客户端时间后,产生的倒计时时间错误或者程序假死等;(pc版淘宝倒计时无时间校准功能)ios
模版自定义:使用者可根据须要自定义模版,将根据模版的关键字进行时间格式的换算及模版展示逻辑的转换,甚至能够跳过特定的时间顺序,随意组合时间特性,以下:git
a、时间随意组合:
输入'$Y年,$W周, $m:$s' => 'x年,x周, x:x'es6
b、模版展示逻辑:
输入'$isBefore{即将开始}' => '即将开始'
or 简单的“或运算”:输入'$isBefore||$isIng{倒计时运行中}' => '倒计时运行中'github
c、时间占位符:正则表达式
占位符列表:[$Y(年), $M(月), $W(周), $D(日), $h(时), $m(分), $s(秒), $_100ms(100毫秒)];算法
模版替换方法:将取到每类占位符的数量,从而将数值按照占位符数量进行填坑;axios
坑位的填充算法:坑位大于数值,数值前补‘0’;坑位小于数值,多余数值填入第一个坑位;示例以下:promise
``` // 剩余时间 restTime = { day: 112, minute: 4, second: 15 } // 输入模版 template = [ '<span>$D</span>', '<span>$D</span>', 'days,' '<span>$m</span>', '<span>$m</span>', ',' '<span>$s</span>', '<span>$s</span>' ].join('') => // 编译结果 resultTemplate = [ '<span>11</span>', '<span>2</span>', 'days,' '<span>0</span>', '<span>4</span>', ',' '<span>1</span>', '<span>5</span>' ].join('')
```浏览器
单元测试:
增长了类方法的单元测试,使用mocha平台和chai断言库,从而下降了开发、调试成本;有些功能开发和验证,均可经过跑单元测试直接拿到,并不须要将这个页面跑起来~~
图2-1 秒杀组件流程图
流程分析:
a、时间处理:在整个流程中,涉及许多时间的运算,因此将时间转换成统一的数值,将简化运算;另输入的日期可能带有'-',在ios中没法识别,转换函数中作了兼容处理;
b、客户端时间校准:该流程包括“验证客户端时间异常”,及“校准”,两个环节。第一个环节,经过将当前客户端时间与上次客户端时间的差值,与异常阈值进行比对得出,该阈值须要大于倒计时during。第二个环节,经过获取服务器时间的回调函数给出,该回调函数返回promise对象,其resolve给出{success, serverTime},经过这种封装,将业务层与组件逻辑进行分离。
c、编译:
3.一、参数
template: 倒计时渲染的模版,其中包含:
a、展示/显示命令:$isBefore$isIng$isAfter 和 或运算(||)
如:$isBefore{xxx} 若是状态为未开始,则露出xxx,不然不显示;
($isIng||$isBefore||$isAfter{xxx},支持以上三个命令的或逻辑)
b、占位符[$Y(年), $M(月), $W(周), $D(日), $h(时), $m(分), $s(秒), $_100ms(100毫秒)]
若是包含$W,则日不大于7!
endSeckillCb: 秒杀结束时的回调。[无参数同perCb]
3.二、调用
import Seckill from './seckill' new Seckill({ endTime: '2018-3-29 11:00:00', startTime: '2018-3-23 15:00:00', getServerTime: () => { return new Promise((resolve, reject) => { axios.get('/common/getNow').then(({data: {success, result}}) => { resolve({ success, serverTime: result }) }) }) } }).init()
UI渲染如图:
图3-2-1 默认template渲染图
3.三、单元测试
命令:mocha --compilers js:babel-core/register ./seckill.test.js
经过使用编译参数,支持es6语法~
引用:
import Seckill from './seckill' import { expect } from 'chai' const seckillObj = new Seckill() const Util = { _formatDate: seckillObj._formatDate, _currServerTime: seckillObj._currServerTime }
须要留意,再测试类时,须要进行new生成实例对象,再对其方法进行单元测试;另,使用es6的class生成的类,不能枚举,因此,没法使用Object.assign方法,直接将对象方法进行拷贝,因此,一些工具函数,需手动复制。
如检测数据方法是否正确:
describe('expect',function(){ it('checkAFormatData_required',function(){ expect(seckillObj._checkAFormatData.apply(Object.assign({ getServerTime: function() {}, startTime: '2018-11-12 12:12:12', endTime: '2018-11-13 12:12:12', }, Util))).to.be.ok; }); });
经过使用将工具函数手动放入Util对象当中,再传递给当前做用域。
而有些状况下,无需使用实际的函数方法进行测试,可重置依赖的函数,从而下降单元测试的藕合度,提高灵活性和错误定位能力,如:
// 编译模版显示隐藏逻辑 describe('expect',function(){ it('compileDisplay',function(){ expect(seckillObj._compileDisplay.call({ _isIng: () => true, _isAfter: () => false, _isBefore: () => false }, '$isIng{<span>即将开始</span>}')).to.be.equal('<span>即将开始</span>') }); });
上述测试代码,若是使用实际的_isIng()等状态函数时,将须要传入额外的startTime、endTime、format函数等,这样依赖一层层往上传递,测试将变得复杂。而这些状态函数、format函数等,都已经通过了自身的单元测试,无需再拿来重测。对于该显示隐藏的函数单元来讲,只须要拿到各状态的布尔值,即可完成该编译单元的独立测试,所以,重置状态函数,返回须要的状态布尔值即可。
单元测试结果如图:
图3-3-1 单元测试结果图
3.四、UI渲染个性化
在当前提供的模版逻辑和占位符没法知足UI须要的状况下,可经过使用perCb来实现个性化定制。因为perCb回调是在每一个倒计时中进行调用,且其调用位置位于template模版挂载以后,所以此时将#seckill的内容置换掉,将实现这一特定的需求。但须要留意的是,perCb中返回的time对象由模版的占位符计算得出,所以,须要在模版中给出所需的占位符。代码以下:
new Seckill({ template: '<p style="display:none">$Y $M $W $D $h $m $s $_100ms</p>', endTime: '2019-4-29 11:00:00', startTime: '2018-3-23 15:00:00', getServerTime: () => { return new Promise((resolve, reject) => { axios.get('/common/getNow').then(({data: {success, result}}) => { resolve({ success, serverTime: result }) }) }) }, perCb: ({time, state}) => { document.querySelector('#seckill').innerHTML = [ '<p style="..."> ' + time.year + ' 年</p>', '<p style="..."> ' + time.month + ' 月</p>', '<p style="..."> ' + time.day + ' 日</p>', '<p style="..."> ' + time.second + ' 秒</p>' ].join('') console.log('per activity', time, state) } }).init()
控制台捕获消息及UI渲染结果以下:
图3-4-1 控制台捕获数据图
图3-4-2 个性化定制UI渲染图
tips: a、在输入的template中,请将DOM元素设置display:none,防止页面抖动~~
b、在个性化渲染中,须要哪些时间,在模版中制定便可;出如今模版中的占位符,都将参与计算,不然不参与。