Chance.js 随机毫秒生成指南:millisecond() 的用法、取值范围与底层实现
Chance.js 随机毫秒生成指南:millisecond() 的用法、取值范围与底层实现
Chance.js 是一个用于 JavaScript 的随机数据生成工具库,其时间(time)模块提供从毫秒、秒、分钟、小时到日期、时间戳在内的一整套时钟数据生成能力。本篇指南聚焦于其中的 chance.millisecond(),讲解它的基本用法、返回值的取值范围与分布逻辑、底层随机数实现,以及它与 hour()、minute()、second()、date()、timestamp() 等相邻 API 的组合应用,帮助你在生成时钟时间、日志时间戳或测试数据时准确使用这一方法。
基本用法
millisecond() 的调用方式非常简单,不需要任何参数:
// usage
chance.millisecond()
调用后返回一个随机的毫秒数,例如:
chance.millisecond();
=> 729
从官方文档(docs/time/millisecond.md)的描述来看,它的设计初衷是"生成一个随机的毫秒数,用于构造时钟时间"。默认情况下,返回值的范围是 0 到 999(含两端),正好对应真实时钟中毫秒字段 0~999 的合法区间。
取值范围与随机性:源码级验证
要理解这个取值范围为何是 0~999,可以直接查看核心源码 chance.js 中的实现:
Chance.prototype.millisecond = function () {
return this.natural({max: 999});
};
也就是说,millisecond() 本质上是 natural({max: 999}) 的一次简化封装。由于 natural() 的默认 min 为 0(见 chance.js),因此实际返回区间为闭区间 [0, 999],共计 1000 个可能取值,与真实毫秒字段一一对应:
- 最小值:
0(对应:00.000) - 最大值:
999(对应:00.999) - 全部取值:
0, 1, 2, ..., 998, 999
从源码结构看,millisecond() 不接受任何自定义参数——它刻意保持固定范围,以保证生成的毫秒值始终是合法的时钟时间组成部分。如果你需要"自然数"层面更灵活的范围控制,应当直接使用 chance.natural()。
底层随机链:millisecond → natural → integer → MT
millisecond() 虽然只有一行代码,但它背后是一条完整的随机数调用链,理解这条链有助于判断输出值的随机性与分布:
Chance.prototype.millisecond调用this.natural({max: 999});- natural() 通过
initOptions补全默认值{min: 0, max: MAX_INT},在未传min时取0,然后校验min不小于 0,最终委托给integer(options); - integer() 采用
Math.floor(this.random() * (max - min + 1) + min)计算均匀分布的整数; this.random()在构造函数中绑定为this.mt.random(this.seed)(见 chance.js),即基于 Mersenne Twister(梅森旋转) 伪随机数生成器产生[0, 1)区间的浮点数,种子可通过new Chance(seed)或chance.seed(seed)注入以保证结果可复现。
由于 integer() 使用闭区间公式 max - min + 1,millisecond() 的 1000 个取值在统计上是近似均匀分布的,适合用于模拟真实时钟毫秒字段。
与时间模块其他 API 的组合
millisecond() 在 Chance 的时间模块中并非孤立存在,它通常与 hour()、minute()、second() 一起构成完整的时钟字段集合。相关 API 的默认区间如下(均可在 chance.js 的时间段代码中确认):
| API | 默认区间 | 说明 |
|---|---|---|
chance.millisecond() |
0 ~ 999 |
毫秒,不支持自定义参数 |
chance.second() |
0 ~ 59 |
秒,支持 {min, max} 参数 |
chance.minute() |
0 ~ 59 |
分钟,支持 {min, max} 参数,与 second() 共用同一实现 |
chance.hour() |
1 ~ 12 |
小时,支持 {twentyfour: true} 切换为 0 ~ 23,亦支持 {min, max} |
例如,手动组装一个完整的随机时钟时间:
var h = chance.hour({twentyfour: true});
var m = chance.minute();
var s = chance.second();
var ms = chance.millisecond();
console.log(h + ':' + m + ':' + s + '.' + ms);
// 可能的输出:23:41:07.729
注意:minute() 与 second() 的实现通过 Chance.prototype.minute = Chance.prototype.second = function (options) 共享同一函数体(见 chance.js),并使用 testRange 校验参数不能越界;而 millisecond() 因为区间由时钟语义固定,没有开放参数入口。
在 date() 中的内部集成
millisecond() 不仅可以直接调用,还被 date() 在生成随机日期时内部使用。查看 chance.js 中 date() 的实现:
options = initOptions(options, {
year: parseInt(this.year(), 10),
month: m.numeric - 1,
day: this.natural({min: 1, max: daysInMonth}),
hour: this.hour({twentyfour: true}),
minute: this.minute(),
second: this.second(),
millisecond: this.millisecond(),
american: true,
string: false
});
date = new Date(options.year, options.month, options.day, options.hour, options.minute, options.second, options.millisecond);
也就是说,每次调用 chance.date() 时,日期对象中的毫秒字段正是由 millisecond() 提供,最终传入 JavaScript 原生 new Date(year, month, day, hour, minute, second, millisecond) 构造器。这印证了官方文档中"idea is for generating a clock time"的定位——millisecond() 是 Chance 内部构造完整时间值的最小粒度组件。
与之相关的两个时间 API 也值得了解:
chance.hammertime()(见 chance.js):直接返回date().getTime(),即包含毫秒精度的时间戳(毫秒数)。chance.timestamp()(见 docs/time/timestamp.md):返回标准的 Unix 时间戳,即自 1970 年 1 月 1 日以来的秒数(如576556683),与毫秒粒度的时间戳不同,二者不要混用。
测试与验证
Chance 的测试体系(基于 Tape 与 lodash 断言)覆盖了时间模块的核心 API,相关用例集中在 test/test.time.js。其中:
date()相关的测试验证了返回值为Date对象、支持american/string选项、{year}/{month}/{day}固定默认值以及min/max区间约束;hour()、minute()、second()均有针对默认区间与min/max自定义范围的测试用例;hammertime()的测试断言其返回值是大于 0 且小于8640000000000000的数字。
你可以在本地仓库中运行测试来验证行为:
npm install
npm test
虽然仓库中没有为 millisecond() 单独编写断言,但通过 date() 与 hammertime() 的用例,可以确认包含毫秒在内的完整时间生成链路是经过验证的。
实战小结
chance.millisecond()无参数调用,返回0 ~ 999的随机毫秒值,适合用于模拟时钟时间的毫秒字段;- 底层由
natural({max: 999})实现,默认min为 0,全部 1000 个取值近似均匀分布; - 随机源为 Mersenne Twister 算法,可通过种子控制结果可复现;
- 配合
hour()、minute()、second()可组装完整时钟时间;date()内部已自动集成该方法的输出; - 若需要秒级 Unix 时间戳,使用
chance.timestamp();若需要毫秒级时间戳,使用chance.hammertime()。
如果需要更精细的毫秒范围控制,建议直接使用 chance.natural({min: 0, max: 999}) 或在其基础上扩展,因为 millisecond() 出于时钟语义的考虑保持固定区间、不接收参数。