@cdlab996/genid
Advanced tools
+85
-237
@@ -1,29 +0,54 @@ | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| //#region src/types/index.ts | ||
| /** | ||
| * ID 生成算法类型 | ||
| */ | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| //#region src/types.ts | ||
| /** ID 生成算法类型 */ | ||
| let GenidMethod = /* @__PURE__ */ function(GenidMethod) { | ||
| /** 漂移算法(推荐用于高性能场景) */ | ||
| /** 漂移算法(推荐,高并发下可突破每毫秒序列号上限) */ | ||
| GenidMethod[GenidMethod["DRIFT"] = 1] = "DRIFT"; | ||
| /** 传统算法 */ | ||
| /** 传统算法(序列号耗尽时等待下一毫秒) */ | ||
| GenidMethod[GenidMethod["TRADITIONAL"] = 2] = "TRADITIONAL"; | ||
| return GenidMethod; | ||
| }({}); | ||
| //#endregion | ||
| //#region src/index.ts | ||
| //#region src/config.ts | ||
| /** 将用户配置与默认值合并,返回完整内部配置 */ | ||
| function initConfig(options) { | ||
| const config = { | ||
| workerId: options.workerId, | ||
| method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT, | ||
| baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(), | ||
| workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6, | ||
| seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6, | ||
| maxSeqNumber: 0, | ||
| minSeqNumber: 0, | ||
| topOverCostCount: 0 | ||
| }; | ||
| config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1; | ||
| config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5; | ||
| config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3; | ||
| return config; | ||
| } | ||
| /** 校验配置合法性,不合法则抛出 Error */ | ||
| function validateConfig(config) { | ||
| const { workerId, baseTime, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config; | ||
| if (baseTime > Date.now()) throw new Error("[GenidOptimized] baseTime 不能大于当前时间"); | ||
| if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间"); | ||
| if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间"); | ||
| if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22"); | ||
| const maxWorkerId = (1 << workerIdBitLength) - 1; | ||
| if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`); | ||
| if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)"); | ||
| if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber"); | ||
| } | ||
| //#endregion | ||
| //#region src/genid.ts | ||
| /** | ||
| * 优化版 Snowflake ID 生成器 | ||
| * 基于 Snowflake 算法的分布式唯一 ID 生成器 | ||
| * | ||
| * 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。 | ||
| * - 漂移算法:高并发下借用未来时间戳,突破每毫秒序列号上限 | ||
| * - 时钟回拨:使用保留序列号(0-4)优雅降级,不阻塞生成 | ||
| * - 非线程安全,每个 Worker/进程应使用独立实例和不同 workerId | ||
| * | ||
| * 特性: | ||
| * - 漂移算法:提升高并发下的性能 | ||
| * - 优雅处理时钟回拨,不阻塞生成 | ||
| * - 可配置的位长度,灵活性高 | ||
| * - 支持传统和漂移两种生成方法 | ||
| * | ||
| * ⚠️ 注意:此实例不是线程安全的,每个 Worker/进程应该创建独立的实例并使用不同的 workerId | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
@@ -47,25 +72,6 @@ var GenidOptimized = class { | ||
| _stats; | ||
| /** | ||
| * 构造函数,初始化 ID 生成器 | ||
| * | ||
| * @param {Object} options - 配置选项 | ||
| * @param {number} options.workerId - 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) | ||
| * @param {GenidMethod} [options.method=GenidMethod.DRIFT] - 算法类型 | ||
| * @param {number} [options.baseTime=1577836800000] - 起始时间戳(毫秒,默认:2020-01-01) | ||
| * @param {number} [options.workerIdBitLength=6] - 工作节点 ID 的位数(1-15,默认:6) | ||
| * @param {number} [options.seqBitLength=6] - 序列号的位数(3-21,默认:6) | ||
| * @param {number} [options.maxSeqNumber] - 最大序列号(默认:2^seqBitLength-1) | ||
| * @param {number} [options.minSeqNumber=5] - 最小序列号(默认:5,0-4 保留) | ||
| * @param {number} [options.topOverCostCount=2000] - 最大漂移次数(默认:2000) | ||
| * | ||
| * @throws {Error} 如果缺少 workerId 或配置无效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
| constructor(options) { | ||
| if (options.workerId === void 0 || options.workerId === null) throw new Error("[GenidOptimized] workerId 是必须参数"); | ||
| const config = this._initConfig(options); | ||
| this._validateConfig(config); | ||
| const config = initConfig(options); | ||
| validateConfig(config); | ||
| this._initVariables(config); | ||
@@ -79,45 +85,2 @@ this._stats = { | ||
| } | ||
| /** | ||
| * 初始化配置,设置默认值 | ||
| * @private | ||
| * @param {Object} options - 用户提供的配置 | ||
| * @returns {Object} 合并后的配置对象 | ||
| */ | ||
| _initConfig(options) { | ||
| const config = { | ||
| workerId: options.workerId, | ||
| method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT, | ||
| baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(), | ||
| workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6, | ||
| seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6, | ||
| maxSeqNumber: 0, | ||
| minSeqNumber: 0, | ||
| topOverCostCount: 0 | ||
| }; | ||
| config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1; | ||
| config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5; | ||
| config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3; | ||
| return config; | ||
| } | ||
| /** | ||
| * 验证配置参数的有效性 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| * @throws {Error} 如果配置无效 | ||
| */ | ||
| _validateConfig(config) { | ||
| const { workerId, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config; | ||
| if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间"); | ||
| if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间"); | ||
| if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22"); | ||
| const maxWorkerId = (1 << workerIdBitLength) - 1; | ||
| if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`); | ||
| if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)"); | ||
| if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber"); | ||
| } | ||
| /** | ||
| * 初始化实例变量 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| */ | ||
| _initVariables(config) { | ||
@@ -140,15 +103,7 @@ this.method = BigInt(config.method); | ||
| } | ||
| /** | ||
| * 获取当前时间戳(相对于 baseTime 的毫秒数) | ||
| * @private | ||
| * @returns {bigint} 当前时间戳 | ||
| */ | ||
| /** 获取相对于 baseTime 的当前时间戳 */ | ||
| _getCurrentTimeTick() { | ||
| return BigInt(Date.now()) - this.baseTime; | ||
| } | ||
| /** | ||
| * 等待下一毫秒 | ||
| * @private | ||
| * @returns {bigint} 下一毫秒时间戳 | ||
| */ | ||
| /** 自旋等待直到时间前进到下一毫秒 */ | ||
| _getNextTimeTick() { | ||
@@ -160,8 +115,3 @@ let timeTick = this._getCurrentTimeTick(); | ||
| spinCount++; | ||
| if (spinCount > maxSpinCount) | ||
| /** | ||
| * 如果自旋太多次,强制返回当前时间 + 1 | ||
| * 这种情况理论上不应该发生,除非系统时间出现严重问题 | ||
| */ | ||
| return this._lastTimeTick + 1n; | ||
| if (spinCount > maxSpinCount) return this._lastTimeTick + 1n; | ||
| timeTick = this._getCurrentTimeTick(); | ||
@@ -171,8 +121,3 @@ } | ||
| } | ||
| /** | ||
| * 根据组件计算 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 组装 ID:timestamp | workerId | sequence,并自增序列号 */ | ||
| _calcId(useTimeTick) { | ||
@@ -184,8 +129,3 @@ const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + this._currentSeqNumber; | ||
| } | ||
| /** | ||
| * 计算时钟回拨时的 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 时钟回拨时组装 ID,使用保留序列号(0-4)避免冲突 */ | ||
| _calcTurnBackId(useTimeTick) { | ||
@@ -197,7 +137,3 @@ const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + BigInt(this._turnBackIndex); | ||
| } | ||
| /** | ||
| * 处理漂移情况(漂移算法) | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 漂移状态下生成 ID */ | ||
| _nextOverCostId() { | ||
@@ -238,7 +174,3 @@ const currentTimeTick = this._getCurrentTimeTick(); | ||
| } | ||
| /** | ||
| * 正常生成 ID | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 正常状态下生成 ID */ | ||
| _nextNormalId() { | ||
@@ -260,2 +192,9 @@ const currentTimeTick = this._getCurrentTimeTick(); | ||
| } | ||
| if (this._turnBackTimeTick >= this._lastTimeTick) { | ||
| this._turnBackTimeTick = 0n; | ||
| this._turnBackIndex = 0; | ||
| this._lastTimeTick = this._getNextTimeTick(); | ||
| this._currentSeqNumber = this.minSeqNumber; | ||
| return this._calcId(this._lastTimeTick); | ||
| } | ||
| return this._calcTurnBackId(this._turnBackTimeTick); | ||
@@ -274,2 +213,7 @@ } | ||
| if (this._currentSeqNumber > this.maxSeqNumber) { | ||
| if (this.method === BigInt(GenidMethod.TRADITIONAL)) { | ||
| this._lastTimeTick = this._getNextTimeTick(); | ||
| this._currentSeqNumber = this.minSeqNumber; | ||
| return this._calcId(this._lastTimeTick); | ||
| } | ||
| this._beginOverCostAction(currentTimeTick); | ||
@@ -285,36 +229,10 @@ this._lastTimeTick++; | ||
| } | ||
| _beginOverCostAction(_useTimeTick) {} | ||
| _endOverCostAction(_useTimeTick) {} | ||
| _beginTurnBackAction(_useTimeTick) {} | ||
| _endTurnBackAction(_useTimeTick) {} | ||
| /** | ||
| * 钩子函数:开始漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| * 生成 ID,返回 number。超出安全整数范围时抛错。 | ||
| * @throws 当 ID >= Number.MAX_SAFE_INTEGER + 1 时 | ||
| */ | ||
| _beginOverCostAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:结束漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _endOverCostAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:开始时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _beginTurnBackAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:结束时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _endTurnBackAction(useTimeTick) {} | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {number} 唯一 ID(Number 类型) | ||
| * @throws {Error} 如果 ID 超出 JavaScript 安全整数范围 | ||
| * | ||
| * @example | ||
| * const id = genid.nextNumber(); | ||
| * console.log(id); // 123456789012345 | ||
| */ | ||
| nextNumber() { | ||
@@ -325,13 +243,3 @@ const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * 如果 ID 在安全范围内返回 Number,否则返回 BigInt | ||
| * | ||
| * @returns {number|bigint} 唯一 ID | ||
| * | ||
| * @example | ||
| * const id = genid.nextId(); | ||
| * console.log(typeof id); // 'number' 或 'bigint' | ||
| */ | ||
| /** 生成 ID,安全范围内返回 number,否则返回 bigint */ | ||
| nextId() { | ||
@@ -341,25 +249,7 @@ const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {bigint} 唯一 ID(BigInt 类型) | ||
| * | ||
| * @example | ||
| * const id = genid.nextBigId(); | ||
| * console.log(id); // 123456789012345678n | ||
| */ | ||
| /** 生成 ID,始终返回 bigint */ | ||
| nextBigId() { | ||
| return this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 批量生成 ID | ||
| * | ||
| * @param {number} count - 要生成的 ID 数量 | ||
| * @param {boolean} [asBigInt=false] - 是否返回 BigInt 数组 | ||
| * @returns {Array<number|bigint>} 唯一 ID 数组 | ||
| * | ||
| * @example | ||
| * const ids = genid.nextBatch(100); | ||
| * const bigIds = genid.nextBatch(100, true); | ||
| */ | ||
| /** 批量生成 ID */ | ||
| nextBatch(count, asBigInt = false) { | ||
@@ -372,20 +262,7 @@ if (count <= 0) throw new Error("[GenidOptimized] 批量生成数量必须大于 0"); | ||
| /** | ||
| * 解析 ID,提取其组成部分 | ||
| * 解析 ID,提取时间戳、workerId、序列号 | ||
| * | ||
| * @param {number|bigint|string} id - 要解析的 ID | ||
| * @returns {Object} 解析结果 | ||
| * @returns {Date} return.timestamp - 生成时间戳 | ||
| * @returns {number} return.timestampMs - 时间戳(毫秒) | ||
| * @returns {number} return.workerId - 工作节点 ID | ||
| * @returns {number} return.sequence - 序列号 | ||
| * | ||
| * @example | ||
| * const info = genid.parse(id); | ||
| * console.log(info); | ||
| * // { | ||
| * // timestamp: Date, | ||
| * // timestampMs: 1609459200000, | ||
| * // workerId: 1, | ||
| * // sequence: 42 | ||
| * // } | ||
| * genid.parse(id) | ||
| * // { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 } | ||
| */ | ||
@@ -406,11 +283,3 @@ parse(id) { | ||
| } | ||
| /** | ||
| * 获取生成器统计信息 | ||
| * | ||
| * @returns {Object} 统计数据 | ||
| * | ||
| * @example | ||
| * const stats = genid.getStats(); | ||
| * console.log(stats); | ||
| */ | ||
| /** 获取运行统计信息 */ | ||
| getStats() { | ||
@@ -428,5 +297,3 @@ const uptime = Date.now() - this._stats.startTime; | ||
| } | ||
| /** | ||
| * 重置统计数据 | ||
| */ | ||
| /** 重置统计数据 */ | ||
| resetStats() { | ||
@@ -440,7 +307,3 @@ this._stats = { | ||
| } | ||
| /** | ||
| * 获取配置信息 | ||
| * | ||
| * @returns {Object} 配置详情 | ||
| */ | ||
| /** 获取当前配置信息 */ | ||
| getConfig() { | ||
@@ -464,14 +327,4 @@ const maxWorkerId = (1 << Number(this.workerIdBitLength)) - 1; | ||
| /** | ||
| * 验证 ID 是否为有效的 Snowflake ID | ||
| * | ||
| * @param {number|bigint|string} id - 要验证的 ID | ||
| * @param {boolean} [strictWorkerId=false] - 是否严格验证 workerId 必须匹配当前实例 | ||
| * @returns {boolean} ID 是否有效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| * genid.isValid(id); // true | ||
| * genid.isValid(12345); // false | ||
| * genid.isValid(id, true); // true (workerId 匹配) | ||
| * 验证 ID 是否为当前配置下合法的 Snowflake ID | ||
| * @param strictWorkerId - 为 true 时要求 workerId 匹配当前实例 | ||
| */ | ||
@@ -499,8 +352,3 @@ isValid(id, strictWorkerId = false) { | ||
| } | ||
| /** | ||
| * 将 ID 格式化为二进制字符串以便调试 | ||
| * | ||
| * @param {number|bigint|string} id - 要格式化的 ID | ||
| * @returns {string} 格式化的二进制表示 | ||
| */ | ||
| /** 将 ID 格式化为带标注的二进制字符串(调试用) */ | ||
| formatBinary(id) { | ||
@@ -523,4 +371,4 @@ const idBigInt = BigInt(id); | ||
| }; | ||
| //#endregion | ||
| exports.GenidOptimized = GenidOptimized; | ||
| exports.GenidMethod = GenidMethod; | ||
| exports.GenidOptimized = GenidOptimized; |
+71
-238
@@ -1,39 +0,51 @@ | ||
| //#region src/types/index.d.ts | ||
| /** | ||
| * ID 生成算法类型 | ||
| */ | ||
| //#region src/types.d.ts | ||
| /** ID 生成算法类型 */ | ||
| declare enum GenidMethod { | ||
| /** 漂移算法(推荐用于高性能场景) */ | ||
| /** 漂移算法(推荐,高并发下可突破每毫秒序列号上限) */ | ||
| DRIFT = 1, | ||
| /** 传统算法 */ | ||
| /** 传统算法(序列号耗尽时等待下一毫秒) */ | ||
| TRADITIONAL = 2 | ||
| } | ||
| /** | ||
| * ID 生成器配置选项 | ||
| */ | ||
| /** ID 生成器构造选项 */ | ||
| interface GenidOptions { | ||
| /** 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) */ | ||
| /** 工作节点 ID(必须,范围 0 到 2^workerIdBitLength-1) */ | ||
| workerId: number; | ||
| /** 算法类型(默认:GenidMethod.DRIFT) */ | ||
| /** 算法类型(默认:DRIFT) */ | ||
| method?: GenidMethod; | ||
| /** 起始时间戳,单位:毫秒(默认:1577836800000,即 2020-01-01 00:00:00) */ | ||
| /** 起始时间戳/毫秒(默认:2020-01-01) */ | ||
| baseTime?: number; | ||
| /** 工作节点 ID 的位数(范围:1-15,默认:6) */ | ||
| /** 工作节点 ID 位数(1-15,默认:6) */ | ||
| workerIdBitLength?: number; | ||
| /** 序列号的位数(范围:3-21,默认:6) */ | ||
| /** 序列号位数(3-21,默认:6) */ | ||
| seqBitLength?: number; | ||
| /** 最大序列号(默认:2^seqBitLength - 1) */ | ||
| maxSeqNumber?: number; | ||
| /** 最小序列号(默认:5,0-4 保留用于时钟回拨处理) */ | ||
| /** 最小序列号(默认:5,0-4 保留用于时钟回拨) */ | ||
| minSeqNumber?: number; | ||
| /** 最大漂移次数,超过后等待下一毫秒(默认:2000) */ | ||
| /** 最大漂移次数(默认:2000) */ | ||
| topOverCostCount?: number; | ||
| } | ||
| /** | ||
| * ID 解析结果 | ||
| */ | ||
| /** 内部配置(所有字段必填,由 initConfig 生成) */ | ||
| interface GenidConfig { | ||
| workerId: number; | ||
| method: GenidMethod; | ||
| baseTime: number; | ||
| workerIdBitLength: number; | ||
| seqBitLength: number; | ||
| maxSeqNumber: number; | ||
| minSeqNumber: number; | ||
| topOverCostCount: number; | ||
| } | ||
| /** 内部统计数据(BigInt 确保大数精度) */ | ||
| interface Stats { | ||
| totalGenerated: bigint; | ||
| overCostCount: bigint; | ||
| turnBackCount: bigint; | ||
| startTime: number; | ||
| } | ||
| /** ID 解析结果 */ | ||
| interface ParseResult { | ||
| /** ID 生成时间(Date 对象) */ | ||
| /** 生成时间 */ | ||
| timestamp: Date; | ||
| /** ID 生成时间戳,单位:毫秒 */ | ||
| /** 生成时间戳/毫秒 */ | ||
| timestampMs: number; | ||
@@ -45,58 +57,39 @@ /** 工作节点 ID */ | ||
| } | ||
| /** | ||
| * 统计信息结果(对外暴露,使用 Number 类型) | ||
| */ | ||
| /** 对外统计信息 */ | ||
| interface StatsResult { | ||
| /** 总生成 ID 数量 */ | ||
| totalGenerated: number; | ||
| /** 漂移次数 */ | ||
| overCostCount: number; | ||
| /** 时钟回拨次数 */ | ||
| turnBackCount: number; | ||
| /** 运行时长,单位:毫秒 */ | ||
| /** 运行时长/毫秒 */ | ||
| uptimeMs: number; | ||
| /** 平均每秒生成 ID 数量 */ | ||
| avgPerSecond: number; | ||
| /** 当前状态(OVER_COST: 漂移中, NORMAL: 正常) */ | ||
| currentState: 'OVER_COST' | 'NORMAL'; | ||
| } | ||
| /** | ||
| * 配置信息结果 | ||
| */ | ||
| /** 配置信息 */ | ||
| interface ConfigResult { | ||
| /** 算法类型(DRIFT: 漂移算法, TRADITIONAL: 传统算法) */ | ||
| method: 'DRIFT' | 'TRADITIONAL'; | ||
| /** 当前工作节点 ID */ | ||
| workerId: number; | ||
| /** 工作节点 ID 范围(格式:"0-63") */ | ||
| /** 格式:"0-63" */ | ||
| workerIdRange: string; | ||
| /** 序列号范围(格式:"5-63") */ | ||
| /** 格式:"5-63" */ | ||
| sequenceRange: string; | ||
| /** 最大序列号值 */ | ||
| maxSequence: number; | ||
| /** 每毫秒可生成的 ID 数量 */ | ||
| idsPerMillisecond: number; | ||
| /** 起始时间(Date 对象) */ | ||
| baseTime: Date; | ||
| /** 时间戳占用的位数 */ | ||
| timestampBits: number; | ||
| /** 工作节点 ID 占用的位数 */ | ||
| workerIdBits: number; | ||
| /** 序列号占用的位数 */ | ||
| sequenceBits: number; | ||
| } | ||
| //#endregion | ||
| //#region src/index.d.ts | ||
| //#region src/genid.d.ts | ||
| /** | ||
| * 优化版 Snowflake ID 生成器 | ||
| * 基于 Snowflake 算法的分布式唯一 ID 生成器 | ||
| * | ||
| * 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。 | ||
| * - 漂移算法:高并发下借用未来时间戳,突破每毫秒序列号上限 | ||
| * - 时钟回拨:使用保留序列号(0-4)优雅降级,不阻塞生成 | ||
| * - 非线程安全,每个 Worker/进程应使用独立实例和不同 workerId | ||
| * | ||
| * 特性: | ||
| * - 漂移算法:提升高并发下的性能 | ||
| * - 优雅处理时钟回拨,不阻塞生成 | ||
| * - 可配置的位长度,灵活性高 | ||
| * - 支持传统和漂移两种生成方法 | ||
| * | ||
| * ⚠️ 注意:此实例不是线程安全的,每个 Worker/进程应该创建独立的实例并使用不同的 workerId | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
@@ -120,214 +113,54 @@ declare class GenidOptimized { | ||
| private _stats; | ||
| /** | ||
| * 构造函数,初始化 ID 生成器 | ||
| * | ||
| * @param {Object} options - 配置选项 | ||
| * @param {number} options.workerId - 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) | ||
| * @param {GenidMethod} [options.method=GenidMethod.DRIFT] - 算法类型 | ||
| * @param {number} [options.baseTime=1577836800000] - 起始时间戳(毫秒,默认:2020-01-01) | ||
| * @param {number} [options.workerIdBitLength=6] - 工作节点 ID 的位数(1-15,默认:6) | ||
| * @param {number} [options.seqBitLength=6] - 序列号的位数(3-21,默认:6) | ||
| * @param {number} [options.maxSeqNumber] - 最大序列号(默认:2^seqBitLength-1) | ||
| * @param {number} [options.minSeqNumber=5] - 最小序列号(默认:5,0-4 保留) | ||
| * @param {number} [options.topOverCostCount=2000] - 最大漂移次数(默认:2000) | ||
| * | ||
| * @throws {Error} 如果缺少 workerId 或配置无效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
| constructor(options: GenidOptions); | ||
| /** | ||
| * 初始化配置,设置默认值 | ||
| * @private | ||
| * @param {Object} options - 用户提供的配置 | ||
| * @returns {Object} 合并后的配置对象 | ||
| */ | ||
| private _initConfig; | ||
| /** | ||
| * 验证配置参数的有效性 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| * @throws {Error} 如果配置无效 | ||
| */ | ||
| private _validateConfig; | ||
| /** | ||
| * 初始化实例变量 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| */ | ||
| private _initVariables; | ||
| /** | ||
| * 获取当前时间戳(相对于 baseTime 的毫秒数) | ||
| * @private | ||
| * @returns {bigint} 当前时间戳 | ||
| */ | ||
| /** 获取相对于 baseTime 的当前时间戳 */ | ||
| private _getCurrentTimeTick; | ||
| /** | ||
| * 等待下一毫秒 | ||
| * @private | ||
| * @returns {bigint} 下一毫秒时间戳 | ||
| */ | ||
| /** 自旋等待直到时间前进到下一毫秒 */ | ||
| private _getNextTimeTick; | ||
| /** | ||
| * 根据组件计算 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 组装 ID:timestamp | workerId | sequence,并自增序列号 */ | ||
| private _calcId; | ||
| /** | ||
| * 计算时钟回拨时的 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 时钟回拨时组装 ID,使用保留序列号(0-4)避免冲突 */ | ||
| private _calcTurnBackId; | ||
| /** | ||
| * 处理漂移情况(漂移算法) | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 漂移状态下生成 ID */ | ||
| private _nextOverCostId; | ||
| /** | ||
| * 正常生成 ID | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 正常状态下生成 ID */ | ||
| private _nextNormalId; | ||
| protected _beginOverCostAction(_useTimeTick: bigint): void; | ||
| protected _endOverCostAction(_useTimeTick: bigint): void; | ||
| protected _beginTurnBackAction(_useTimeTick: bigint): void; | ||
| protected _endTurnBackAction(_useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:开始漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| * 生成 ID,返回 number。超出安全整数范围时抛错。 | ||
| * @throws 当 ID >= Number.MAX_SAFE_INTEGER + 1 时 | ||
| */ | ||
| protected _beginOverCostAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:结束漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _endOverCostAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:开始时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _beginTurnBackAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:结束时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _endTurnBackAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {number} 唯一 ID(Number 类型) | ||
| * @throws {Error} 如果 ID 超出 JavaScript 安全整数范围 | ||
| * | ||
| * @example | ||
| * const id = genid.nextNumber(); | ||
| * console.log(id); // 123456789012345 | ||
| */ | ||
| nextNumber(): number; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * 如果 ID 在安全范围内返回 Number,否则返回 BigInt | ||
| * | ||
| * @returns {number|bigint} 唯一 ID | ||
| * | ||
| * @example | ||
| * const id = genid.nextId(); | ||
| * console.log(typeof id); // 'number' 或 'bigint' | ||
| */ | ||
| /** 生成 ID,安全范围内返回 number,否则返回 bigint */ | ||
| nextId(): number | bigint; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {bigint} 唯一 ID(BigInt 类型) | ||
| * | ||
| * @example | ||
| * const id = genid.nextBigId(); | ||
| * console.log(id); // 123456789012345678n | ||
| */ | ||
| /** 生成 ID,始终返回 bigint */ | ||
| nextBigId(): bigint; | ||
| /** | ||
| * 批量生成 ID | ||
| * | ||
| * @param {number} count - 要生成的 ID 数量 | ||
| * @param {boolean} [asBigInt=false] - 是否返回 BigInt 数组 | ||
| * @returns {Array<number|bigint>} 唯一 ID 数组 | ||
| * | ||
| * @example | ||
| * const ids = genid.nextBatch(100); | ||
| * const bigIds = genid.nextBatch(100, true); | ||
| */ | ||
| /** 批量生成 ID */ | ||
| nextBatch(count: number, asBigInt?: boolean): Array<number | bigint>; | ||
| /** | ||
| * 解析 ID,提取其组成部分 | ||
| * 解析 ID,提取时间戳、workerId、序列号 | ||
| * | ||
| * @param {number|bigint|string} id - 要解析的 ID | ||
| * @returns {Object} 解析结果 | ||
| * @returns {Date} return.timestamp - 生成时间戳 | ||
| * @returns {number} return.timestampMs - 时间戳(毫秒) | ||
| * @returns {number} return.workerId - 工作节点 ID | ||
| * @returns {number} return.sequence - 序列号 | ||
| * | ||
| * @example | ||
| * const info = genid.parse(id); | ||
| * console.log(info); | ||
| * // { | ||
| * // timestamp: Date, | ||
| * // timestampMs: 1609459200000, | ||
| * // workerId: 1, | ||
| * // sequence: 42 | ||
| * // } | ||
| * genid.parse(id) | ||
| * // { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 } | ||
| */ | ||
| parse(id: number | bigint | string): ParseResult; | ||
| /** | ||
| * 获取生成器统计信息 | ||
| * | ||
| * @returns {Object} 统计数据 | ||
| * | ||
| * @example | ||
| * const stats = genid.getStats(); | ||
| * console.log(stats); | ||
| */ | ||
| /** 获取运行统计信息 */ | ||
| getStats(): StatsResult; | ||
| /** | ||
| * 重置统计数据 | ||
| */ | ||
| /** 重置统计数据 */ | ||
| resetStats(): void; | ||
| /** | ||
| * 获取配置信息 | ||
| * | ||
| * @returns {Object} 配置详情 | ||
| */ | ||
| /** 获取当前配置信息 */ | ||
| getConfig(): ConfigResult; | ||
| /** | ||
| * 验证 ID 是否为有效的 Snowflake ID | ||
| * | ||
| * @param {number|bigint|string} id - 要验证的 ID | ||
| * @param {boolean} [strictWorkerId=false] - 是否严格验证 workerId 必须匹配当前实例 | ||
| * @returns {boolean} ID 是否有效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| * genid.isValid(id); // true | ||
| * genid.isValid(12345); // false | ||
| * genid.isValid(id, true); // true (workerId 匹配) | ||
| * 验证 ID 是否为当前配置下合法的 Snowflake ID | ||
| * @param strictWorkerId - 为 true 时要求 workerId 匹配当前实例 | ||
| */ | ||
| isValid(id: number | bigint | string, strictWorkerId?: boolean): boolean; | ||
| /** | ||
| * 将 ID 格式化为二进制字符串以便调试 | ||
| * | ||
| * @param {number|bigint|string} id - 要格式化的 ID | ||
| * @returns {string} 格式化的二进制表示 | ||
| */ | ||
| /** 将 ID 格式化为带标注的二进制字符串(调试用) */ | ||
| formatBinary(id: number | bigint | string): string; | ||
| } | ||
| //#endregion | ||
| export { GenidOptimized }; | ||
| export { ConfigResult, GenidConfig, GenidMethod, GenidOptimized, GenidOptions, ParseResult, Stats, StatsResult }; |
+71
-238
@@ -1,39 +0,51 @@ | ||
| //#region src/types/index.d.ts | ||
| /** | ||
| * ID 生成算法类型 | ||
| */ | ||
| //#region src/types.d.ts | ||
| /** ID 生成算法类型 */ | ||
| declare enum GenidMethod { | ||
| /** 漂移算法(推荐用于高性能场景) */ | ||
| /** 漂移算法(推荐,高并发下可突破每毫秒序列号上限) */ | ||
| DRIFT = 1, | ||
| /** 传统算法 */ | ||
| /** 传统算法(序列号耗尽时等待下一毫秒) */ | ||
| TRADITIONAL = 2 | ||
| } | ||
| /** | ||
| * ID 生成器配置选项 | ||
| */ | ||
| /** ID 生成器构造选项 */ | ||
| interface GenidOptions { | ||
| /** 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) */ | ||
| /** 工作节点 ID(必须,范围 0 到 2^workerIdBitLength-1) */ | ||
| workerId: number; | ||
| /** 算法类型(默认:GenidMethod.DRIFT) */ | ||
| /** 算法类型(默认:DRIFT) */ | ||
| method?: GenidMethod; | ||
| /** 起始时间戳,单位:毫秒(默认:1577836800000,即 2020-01-01 00:00:00) */ | ||
| /** 起始时间戳/毫秒(默认:2020-01-01) */ | ||
| baseTime?: number; | ||
| /** 工作节点 ID 的位数(范围:1-15,默认:6) */ | ||
| /** 工作节点 ID 位数(1-15,默认:6) */ | ||
| workerIdBitLength?: number; | ||
| /** 序列号的位数(范围:3-21,默认:6) */ | ||
| /** 序列号位数(3-21,默认:6) */ | ||
| seqBitLength?: number; | ||
| /** 最大序列号(默认:2^seqBitLength - 1) */ | ||
| maxSeqNumber?: number; | ||
| /** 最小序列号(默认:5,0-4 保留用于时钟回拨处理) */ | ||
| /** 最小序列号(默认:5,0-4 保留用于时钟回拨) */ | ||
| minSeqNumber?: number; | ||
| /** 最大漂移次数,超过后等待下一毫秒(默认:2000) */ | ||
| /** 最大漂移次数(默认:2000) */ | ||
| topOverCostCount?: number; | ||
| } | ||
| /** | ||
| * ID 解析结果 | ||
| */ | ||
| /** 内部配置(所有字段必填,由 initConfig 生成) */ | ||
| interface GenidConfig { | ||
| workerId: number; | ||
| method: GenidMethod; | ||
| baseTime: number; | ||
| workerIdBitLength: number; | ||
| seqBitLength: number; | ||
| maxSeqNumber: number; | ||
| minSeqNumber: number; | ||
| topOverCostCount: number; | ||
| } | ||
| /** 内部统计数据(BigInt 确保大数精度) */ | ||
| interface Stats { | ||
| totalGenerated: bigint; | ||
| overCostCount: bigint; | ||
| turnBackCount: bigint; | ||
| startTime: number; | ||
| } | ||
| /** ID 解析结果 */ | ||
| interface ParseResult { | ||
| /** ID 生成时间(Date 对象) */ | ||
| /** 生成时间 */ | ||
| timestamp: Date; | ||
| /** ID 生成时间戳,单位:毫秒 */ | ||
| /** 生成时间戳/毫秒 */ | ||
| timestampMs: number; | ||
@@ -45,58 +57,39 @@ /** 工作节点 ID */ | ||
| } | ||
| /** | ||
| * 统计信息结果(对外暴露,使用 Number 类型) | ||
| */ | ||
| /** 对外统计信息 */ | ||
| interface StatsResult { | ||
| /** 总生成 ID 数量 */ | ||
| totalGenerated: number; | ||
| /** 漂移次数 */ | ||
| overCostCount: number; | ||
| /** 时钟回拨次数 */ | ||
| turnBackCount: number; | ||
| /** 运行时长,单位:毫秒 */ | ||
| /** 运行时长/毫秒 */ | ||
| uptimeMs: number; | ||
| /** 平均每秒生成 ID 数量 */ | ||
| avgPerSecond: number; | ||
| /** 当前状态(OVER_COST: 漂移中, NORMAL: 正常) */ | ||
| currentState: 'OVER_COST' | 'NORMAL'; | ||
| } | ||
| /** | ||
| * 配置信息结果 | ||
| */ | ||
| /** 配置信息 */ | ||
| interface ConfigResult { | ||
| /** 算法类型(DRIFT: 漂移算法, TRADITIONAL: 传统算法) */ | ||
| method: 'DRIFT' | 'TRADITIONAL'; | ||
| /** 当前工作节点 ID */ | ||
| workerId: number; | ||
| /** 工作节点 ID 范围(格式:"0-63") */ | ||
| /** 格式:"0-63" */ | ||
| workerIdRange: string; | ||
| /** 序列号范围(格式:"5-63") */ | ||
| /** 格式:"5-63" */ | ||
| sequenceRange: string; | ||
| /** 最大序列号值 */ | ||
| maxSequence: number; | ||
| /** 每毫秒可生成的 ID 数量 */ | ||
| idsPerMillisecond: number; | ||
| /** 起始时间(Date 对象) */ | ||
| baseTime: Date; | ||
| /** 时间戳占用的位数 */ | ||
| timestampBits: number; | ||
| /** 工作节点 ID 占用的位数 */ | ||
| workerIdBits: number; | ||
| /** 序列号占用的位数 */ | ||
| sequenceBits: number; | ||
| } | ||
| //#endregion | ||
| //#region src/index.d.ts | ||
| //#region src/genid.d.ts | ||
| /** | ||
| * 优化版 Snowflake ID 生成器 | ||
| * 基于 Snowflake 算法的分布式唯一 ID 生成器 | ||
| * | ||
| * 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。 | ||
| * - 漂移算法:高并发下借用未来时间戳,突破每毫秒序列号上限 | ||
| * - 时钟回拨:使用保留序列号(0-4)优雅降级,不阻塞生成 | ||
| * - 非线程安全,每个 Worker/进程应使用独立实例和不同 workerId | ||
| * | ||
| * 特性: | ||
| * - 漂移算法:提升高并发下的性能 | ||
| * - 优雅处理时钟回拨,不阻塞生成 | ||
| * - 可配置的位长度,灵活性高 | ||
| * - 支持传统和漂移两种生成方法 | ||
| * | ||
| * ⚠️ 注意:此实例不是线程安全的,每个 Worker/进程应该创建独立的实例并使用不同的 workerId | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
@@ -120,214 +113,54 @@ declare class GenidOptimized { | ||
| private _stats; | ||
| /** | ||
| * 构造函数,初始化 ID 生成器 | ||
| * | ||
| * @param {Object} options - 配置选项 | ||
| * @param {number} options.workerId - 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) | ||
| * @param {GenidMethod} [options.method=GenidMethod.DRIFT] - 算法类型 | ||
| * @param {number} [options.baseTime=1577836800000] - 起始时间戳(毫秒,默认:2020-01-01) | ||
| * @param {number} [options.workerIdBitLength=6] - 工作节点 ID 的位数(1-15,默认:6) | ||
| * @param {number} [options.seqBitLength=6] - 序列号的位数(3-21,默认:6) | ||
| * @param {number} [options.maxSeqNumber] - 最大序列号(默认:2^seqBitLength-1) | ||
| * @param {number} [options.minSeqNumber=5] - 最小序列号(默认:5,0-4 保留) | ||
| * @param {number} [options.topOverCostCount=2000] - 最大漂移次数(默认:2000) | ||
| * | ||
| * @throws {Error} 如果缺少 workerId 或配置无效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
| constructor(options: GenidOptions); | ||
| /** | ||
| * 初始化配置,设置默认值 | ||
| * @private | ||
| * @param {Object} options - 用户提供的配置 | ||
| * @returns {Object} 合并后的配置对象 | ||
| */ | ||
| private _initConfig; | ||
| /** | ||
| * 验证配置参数的有效性 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| * @throws {Error} 如果配置无效 | ||
| */ | ||
| private _validateConfig; | ||
| /** | ||
| * 初始化实例变量 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| */ | ||
| private _initVariables; | ||
| /** | ||
| * 获取当前时间戳(相对于 baseTime 的毫秒数) | ||
| * @private | ||
| * @returns {bigint} 当前时间戳 | ||
| */ | ||
| /** 获取相对于 baseTime 的当前时间戳 */ | ||
| private _getCurrentTimeTick; | ||
| /** | ||
| * 等待下一毫秒 | ||
| * @private | ||
| * @returns {bigint} 下一毫秒时间戳 | ||
| */ | ||
| /** 自旋等待直到时间前进到下一毫秒 */ | ||
| private _getNextTimeTick; | ||
| /** | ||
| * 根据组件计算 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 组装 ID:timestamp | workerId | sequence,并自增序列号 */ | ||
| private _calcId; | ||
| /** | ||
| * 计算时钟回拨时的 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 时钟回拨时组装 ID,使用保留序列号(0-4)避免冲突 */ | ||
| private _calcTurnBackId; | ||
| /** | ||
| * 处理漂移情况(漂移算法) | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 漂移状态下生成 ID */ | ||
| private _nextOverCostId; | ||
| /** | ||
| * 正常生成 ID | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 正常状态下生成 ID */ | ||
| private _nextNormalId; | ||
| protected _beginOverCostAction(_useTimeTick: bigint): void; | ||
| protected _endOverCostAction(_useTimeTick: bigint): void; | ||
| protected _beginTurnBackAction(_useTimeTick: bigint): void; | ||
| protected _endTurnBackAction(_useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:开始漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| * 生成 ID,返回 number。超出安全整数范围时抛错。 | ||
| * @throws 当 ID >= Number.MAX_SAFE_INTEGER + 1 时 | ||
| */ | ||
| protected _beginOverCostAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:结束漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _endOverCostAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:开始时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _beginTurnBackAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 钩子函数:结束时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| protected _endTurnBackAction(useTimeTick: bigint): void; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {number} 唯一 ID(Number 类型) | ||
| * @throws {Error} 如果 ID 超出 JavaScript 安全整数范围 | ||
| * | ||
| * @example | ||
| * const id = genid.nextNumber(); | ||
| * console.log(id); // 123456789012345 | ||
| */ | ||
| nextNumber(): number; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * 如果 ID 在安全范围内返回 Number,否则返回 BigInt | ||
| * | ||
| * @returns {number|bigint} 唯一 ID | ||
| * | ||
| * @example | ||
| * const id = genid.nextId(); | ||
| * console.log(typeof id); // 'number' 或 'bigint' | ||
| */ | ||
| /** 生成 ID,安全范围内返回 number,否则返回 bigint */ | ||
| nextId(): number | bigint; | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {bigint} 唯一 ID(BigInt 类型) | ||
| * | ||
| * @example | ||
| * const id = genid.nextBigId(); | ||
| * console.log(id); // 123456789012345678n | ||
| */ | ||
| /** 生成 ID,始终返回 bigint */ | ||
| nextBigId(): bigint; | ||
| /** | ||
| * 批量生成 ID | ||
| * | ||
| * @param {number} count - 要生成的 ID 数量 | ||
| * @param {boolean} [asBigInt=false] - 是否返回 BigInt 数组 | ||
| * @returns {Array<number|bigint>} 唯一 ID 数组 | ||
| * | ||
| * @example | ||
| * const ids = genid.nextBatch(100); | ||
| * const bigIds = genid.nextBatch(100, true); | ||
| */ | ||
| /** 批量生成 ID */ | ||
| nextBatch(count: number, asBigInt?: boolean): Array<number | bigint>; | ||
| /** | ||
| * 解析 ID,提取其组成部分 | ||
| * 解析 ID,提取时间戳、workerId、序列号 | ||
| * | ||
| * @param {number|bigint|string} id - 要解析的 ID | ||
| * @returns {Object} 解析结果 | ||
| * @returns {Date} return.timestamp - 生成时间戳 | ||
| * @returns {number} return.timestampMs - 时间戳(毫秒) | ||
| * @returns {number} return.workerId - 工作节点 ID | ||
| * @returns {number} return.sequence - 序列号 | ||
| * | ||
| * @example | ||
| * const info = genid.parse(id); | ||
| * console.log(info); | ||
| * // { | ||
| * // timestamp: Date, | ||
| * // timestampMs: 1609459200000, | ||
| * // workerId: 1, | ||
| * // sequence: 42 | ||
| * // } | ||
| * genid.parse(id) | ||
| * // { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 } | ||
| */ | ||
| parse(id: number | bigint | string): ParseResult; | ||
| /** | ||
| * 获取生成器统计信息 | ||
| * | ||
| * @returns {Object} 统计数据 | ||
| * | ||
| * @example | ||
| * const stats = genid.getStats(); | ||
| * console.log(stats); | ||
| */ | ||
| /** 获取运行统计信息 */ | ||
| getStats(): StatsResult; | ||
| /** | ||
| * 重置统计数据 | ||
| */ | ||
| /** 重置统计数据 */ | ||
| resetStats(): void; | ||
| /** | ||
| * 获取配置信息 | ||
| * | ||
| * @returns {Object} 配置详情 | ||
| */ | ||
| /** 获取当前配置信息 */ | ||
| getConfig(): ConfigResult; | ||
| /** | ||
| * 验证 ID 是否为有效的 Snowflake ID | ||
| * | ||
| * @param {number|bigint|string} id - 要验证的 ID | ||
| * @param {boolean} [strictWorkerId=false] - 是否严格验证 workerId 必须匹配当前实例 | ||
| * @returns {boolean} ID 是否有效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| * genid.isValid(id); // true | ||
| * genid.isValid(12345); // false | ||
| * genid.isValid(id, true); // true (workerId 匹配) | ||
| * 验证 ID 是否为当前配置下合法的 Snowflake ID | ||
| * @param strictWorkerId - 为 true 时要求 workerId 匹配当前实例 | ||
| */ | ||
| isValid(id: number | bigint | string, strictWorkerId?: boolean): boolean; | ||
| /** | ||
| * 将 ID 格式化为二进制字符串以便调试 | ||
| * | ||
| * @param {number|bigint|string} id - 要格式化的 ID | ||
| * @returns {string} 格式化的二进制表示 | ||
| */ | ||
| /** 将 ID 格式化为带标注的二进制字符串(调试用) */ | ||
| formatBinary(id: number | bigint | string): string; | ||
| } | ||
| //#endregion | ||
| export { GenidOptimized }; | ||
| export { ConfigResult, GenidConfig, GenidMethod, GenidOptimized, GenidOptions, ParseResult, Stats, StatsResult }; |
+83
-235
@@ -1,27 +0,53 @@ | ||
| //#region src/types/index.ts | ||
| /** | ||
| * ID 生成算法类型 | ||
| */ | ||
| //#region src/types.ts | ||
| /** ID 生成算法类型 */ | ||
| let GenidMethod = /* @__PURE__ */ function(GenidMethod) { | ||
| /** 漂移算法(推荐用于高性能场景) */ | ||
| /** 漂移算法(推荐,高并发下可突破每毫秒序列号上限) */ | ||
| GenidMethod[GenidMethod["DRIFT"] = 1] = "DRIFT"; | ||
| /** 传统算法 */ | ||
| /** 传统算法(序列号耗尽时等待下一毫秒) */ | ||
| GenidMethod[GenidMethod["TRADITIONAL"] = 2] = "TRADITIONAL"; | ||
| return GenidMethod; | ||
| }({}); | ||
| //#endregion | ||
| //#region src/index.ts | ||
| //#region src/config.ts | ||
| /** 将用户配置与默认值合并,返回完整内部配置 */ | ||
| function initConfig(options) { | ||
| const config = { | ||
| workerId: options.workerId, | ||
| method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT, | ||
| baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(), | ||
| workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6, | ||
| seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6, | ||
| maxSeqNumber: 0, | ||
| minSeqNumber: 0, | ||
| topOverCostCount: 0 | ||
| }; | ||
| config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1; | ||
| config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5; | ||
| config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3; | ||
| return config; | ||
| } | ||
| /** 校验配置合法性,不合法则抛出 Error */ | ||
| function validateConfig(config) { | ||
| const { workerId, baseTime, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config; | ||
| if (baseTime > Date.now()) throw new Error("[GenidOptimized] baseTime 不能大于当前时间"); | ||
| if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间"); | ||
| if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间"); | ||
| if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22"); | ||
| const maxWorkerId = (1 << workerIdBitLength) - 1; | ||
| if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`); | ||
| if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)"); | ||
| if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber"); | ||
| } | ||
| //#endregion | ||
| //#region src/genid.ts | ||
| /** | ||
| * 优化版 Snowflake ID 生成器 | ||
| * 基于 Snowflake 算法的分布式唯一 ID 生成器 | ||
| * | ||
| * 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。 | ||
| * - 漂移算法:高并发下借用未来时间戳,突破每毫秒序列号上限 | ||
| * - 时钟回拨:使用保留序列号(0-4)优雅降级,不阻塞生成 | ||
| * - 非线程安全,每个 Worker/进程应使用独立实例和不同 workerId | ||
| * | ||
| * 特性: | ||
| * - 漂移算法:提升高并发下的性能 | ||
| * - 优雅处理时钟回拨,不阻塞生成 | ||
| * - 可配置的位长度,灵活性高 | ||
| * - 支持传统和漂移两种生成方法 | ||
| * | ||
| * ⚠️ 注意:此实例不是线程安全的,每个 Worker/进程应该创建独立的实例并使用不同的 workerId | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
@@ -45,25 +71,6 @@ var GenidOptimized = class { | ||
| _stats; | ||
| /** | ||
| * 构造函数,初始化 ID 生成器 | ||
| * | ||
| * @param {Object} options - 配置选项 | ||
| * @param {number} options.workerId - 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1) | ||
| * @param {GenidMethod} [options.method=GenidMethod.DRIFT] - 算法类型 | ||
| * @param {number} [options.baseTime=1577836800000] - 起始时间戳(毫秒,默认:2020-01-01) | ||
| * @param {number} [options.workerIdBitLength=6] - 工作节点 ID 的位数(1-15,默认:6) | ||
| * @param {number} [options.seqBitLength=6] - 序列号的位数(3-21,默认:6) | ||
| * @param {number} [options.maxSeqNumber] - 最大序列号(默认:2^seqBitLength-1) | ||
| * @param {number} [options.minSeqNumber=5] - 最小序列号(默认:5,0-4 保留) | ||
| * @param {number} [options.topOverCostCount=2000] - 最大漂移次数(默认:2000) | ||
| * | ||
| * @throws {Error} 如果缺少 workerId 或配置无效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| */ | ||
| constructor(options) { | ||
| if (options.workerId === void 0 || options.workerId === null) throw new Error("[GenidOptimized] workerId 是必须参数"); | ||
| const config = this._initConfig(options); | ||
| this._validateConfig(config); | ||
| const config = initConfig(options); | ||
| validateConfig(config); | ||
| this._initVariables(config); | ||
@@ -77,45 +84,2 @@ this._stats = { | ||
| } | ||
| /** | ||
| * 初始化配置,设置默认值 | ||
| * @private | ||
| * @param {Object} options - 用户提供的配置 | ||
| * @returns {Object} 合并后的配置对象 | ||
| */ | ||
| _initConfig(options) { | ||
| const config = { | ||
| workerId: options.workerId, | ||
| method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT, | ||
| baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(), | ||
| workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6, | ||
| seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6, | ||
| maxSeqNumber: 0, | ||
| minSeqNumber: 0, | ||
| topOverCostCount: 0 | ||
| }; | ||
| config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1; | ||
| config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5; | ||
| config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3; | ||
| return config; | ||
| } | ||
| /** | ||
| * 验证配置参数的有效性 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| * @throws {Error} 如果配置无效 | ||
| */ | ||
| _validateConfig(config) { | ||
| const { workerId, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config; | ||
| if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间"); | ||
| if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间"); | ||
| if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22"); | ||
| const maxWorkerId = (1 << workerIdBitLength) - 1; | ||
| if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`); | ||
| if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)"); | ||
| if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber"); | ||
| } | ||
| /** | ||
| * 初始化实例变量 | ||
| * @private | ||
| * @param {Object} config - 配置对象 | ||
| */ | ||
| _initVariables(config) { | ||
@@ -138,15 +102,7 @@ this.method = BigInt(config.method); | ||
| } | ||
| /** | ||
| * 获取当前时间戳(相对于 baseTime 的毫秒数) | ||
| * @private | ||
| * @returns {bigint} 当前时间戳 | ||
| */ | ||
| /** 获取相对于 baseTime 的当前时间戳 */ | ||
| _getCurrentTimeTick() { | ||
| return BigInt(Date.now()) - this.baseTime; | ||
| } | ||
| /** | ||
| * 等待下一毫秒 | ||
| * @private | ||
| * @returns {bigint} 下一毫秒时间戳 | ||
| */ | ||
| /** 自旋等待直到时间前进到下一毫秒 */ | ||
| _getNextTimeTick() { | ||
@@ -158,8 +114,3 @@ let timeTick = this._getCurrentTimeTick(); | ||
| spinCount++; | ||
| if (spinCount > maxSpinCount) | ||
| /** | ||
| * 如果自旋太多次,强制返回当前时间 + 1 | ||
| * 这种情况理论上不应该发生,除非系统时间出现严重问题 | ||
| */ | ||
| return this._lastTimeTick + 1n; | ||
| if (spinCount > maxSpinCount) return this._lastTimeTick + 1n; | ||
| timeTick = this._getCurrentTimeTick(); | ||
@@ -169,8 +120,3 @@ } | ||
| } | ||
| /** | ||
| * 根据组件计算 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 组装 ID:timestamp | workerId | sequence,并自增序列号 */ | ||
| _calcId(useTimeTick) { | ||
@@ -182,8 +128,3 @@ const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + this._currentSeqNumber; | ||
| } | ||
| /** | ||
| * 计算时钟回拨时的 ID | ||
| * @private | ||
| * @param {bigint} useTimeTick - 使用的时间戳 | ||
| * @returns {bigint} 计算得到的 ID | ||
| */ | ||
| /** 时钟回拨时组装 ID,使用保留序列号(0-4)避免冲突 */ | ||
| _calcTurnBackId(useTimeTick) { | ||
@@ -195,7 +136,3 @@ const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + BigInt(this._turnBackIndex); | ||
| } | ||
| /** | ||
| * 处理漂移情况(漂移算法) | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 漂移状态下生成 ID */ | ||
| _nextOverCostId() { | ||
@@ -236,7 +173,3 @@ const currentTimeTick = this._getCurrentTimeTick(); | ||
| } | ||
| /** | ||
| * 正常生成 ID | ||
| * @private | ||
| * @returns {bigint} 生成的 ID | ||
| */ | ||
| /** 正常状态下生成 ID */ | ||
| _nextNormalId() { | ||
@@ -258,2 +191,9 @@ const currentTimeTick = this._getCurrentTimeTick(); | ||
| } | ||
| if (this._turnBackTimeTick >= this._lastTimeTick) { | ||
| this._turnBackTimeTick = 0n; | ||
| this._turnBackIndex = 0; | ||
| this._lastTimeTick = this._getNextTimeTick(); | ||
| this._currentSeqNumber = this.minSeqNumber; | ||
| return this._calcId(this._lastTimeTick); | ||
| } | ||
| return this._calcTurnBackId(this._turnBackTimeTick); | ||
@@ -272,2 +212,7 @@ } | ||
| if (this._currentSeqNumber > this.maxSeqNumber) { | ||
| if (this.method === BigInt(GenidMethod.TRADITIONAL)) { | ||
| this._lastTimeTick = this._getNextTimeTick(); | ||
| this._currentSeqNumber = this.minSeqNumber; | ||
| return this._calcId(this._lastTimeTick); | ||
| } | ||
| this._beginOverCostAction(currentTimeTick); | ||
@@ -283,36 +228,10 @@ this._lastTimeTick++; | ||
| } | ||
| _beginOverCostAction(_useTimeTick) {} | ||
| _endOverCostAction(_useTimeTick) {} | ||
| _beginTurnBackAction(_useTimeTick) {} | ||
| _endTurnBackAction(_useTimeTick) {} | ||
| /** | ||
| * 钩子函数:开始漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| * 生成 ID,返回 number。超出安全整数范围时抛错。 | ||
| * @throws 当 ID >= Number.MAX_SAFE_INTEGER + 1 时 | ||
| */ | ||
| _beginOverCostAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:结束漂移操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _endOverCostAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:开始时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _beginTurnBackAction(useTimeTick) {} | ||
| /** | ||
| * 钩子函数:结束时钟回拨操作(可被子类重写) | ||
| * @protected | ||
| * @param {bigint} useTimeTick - 当前时间戳 | ||
| */ | ||
| _endTurnBackAction(useTimeTick) {} | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {number} 唯一 ID(Number 类型) | ||
| * @throws {Error} 如果 ID 超出 JavaScript 安全整数范围 | ||
| * | ||
| * @example | ||
| * const id = genid.nextNumber(); | ||
| * console.log(id); // 123456789012345 | ||
| */ | ||
| nextNumber() { | ||
@@ -323,13 +242,3 @@ const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * 如果 ID 在安全范围内返回 Number,否则返回 BigInt | ||
| * | ||
| * @returns {number|bigint} 唯一 ID | ||
| * | ||
| * @example | ||
| * const id = genid.nextId(); | ||
| * console.log(typeof id); // 'number' 或 'bigint' | ||
| */ | ||
| /** 生成 ID,安全范围内返回 number,否则返回 bigint */ | ||
| nextId() { | ||
@@ -339,25 +248,7 @@ const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 生成下一个 ID | ||
| * | ||
| * @returns {bigint} 唯一 ID(BigInt 类型) | ||
| * | ||
| * @example | ||
| * const id = genid.nextBigId(); | ||
| * console.log(id); // 123456789012345678n | ||
| */ | ||
| /** 生成 ID,始终返回 bigint */ | ||
| nextBigId() { | ||
| return this._isOverCost ? this._nextOverCostId() : this._nextNormalId(); | ||
| } | ||
| /** | ||
| * 批量生成 ID | ||
| * | ||
| * @param {number} count - 要生成的 ID 数量 | ||
| * @param {boolean} [asBigInt=false] - 是否返回 BigInt 数组 | ||
| * @returns {Array<number|bigint>} 唯一 ID 数组 | ||
| * | ||
| * @example | ||
| * const ids = genid.nextBatch(100); | ||
| * const bigIds = genid.nextBatch(100, true); | ||
| */ | ||
| /** 批量生成 ID */ | ||
| nextBatch(count, asBigInt = false) { | ||
@@ -370,20 +261,7 @@ if (count <= 0) throw new Error("[GenidOptimized] 批量生成数量必须大于 0"); | ||
| /** | ||
| * 解析 ID,提取其组成部分 | ||
| * 解析 ID,提取时间戳、workerId、序列号 | ||
| * | ||
| * @param {number|bigint|string} id - 要解析的 ID | ||
| * @returns {Object} 解析结果 | ||
| * @returns {Date} return.timestamp - 生成时间戳 | ||
| * @returns {number} return.timestampMs - 时间戳(毫秒) | ||
| * @returns {number} return.workerId - 工作节点 ID | ||
| * @returns {number} return.sequence - 序列号 | ||
| * | ||
| * @example | ||
| * const info = genid.parse(id); | ||
| * console.log(info); | ||
| * // { | ||
| * // timestamp: Date, | ||
| * // timestampMs: 1609459200000, | ||
| * // workerId: 1, | ||
| * // sequence: 42 | ||
| * // } | ||
| * genid.parse(id) | ||
| * // { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 } | ||
| */ | ||
@@ -404,11 +282,3 @@ parse(id) { | ||
| } | ||
| /** | ||
| * 获取生成器统计信息 | ||
| * | ||
| * @returns {Object} 统计数据 | ||
| * | ||
| * @example | ||
| * const stats = genid.getStats(); | ||
| * console.log(stats); | ||
| */ | ||
| /** 获取运行统计信息 */ | ||
| getStats() { | ||
@@ -426,5 +296,3 @@ const uptime = Date.now() - this._stats.startTime; | ||
| } | ||
| /** | ||
| * 重置统计数据 | ||
| */ | ||
| /** 重置统计数据 */ | ||
| resetStats() { | ||
@@ -438,7 +306,3 @@ this._stats = { | ||
| } | ||
| /** | ||
| * 获取配置信息 | ||
| * | ||
| * @returns {Object} 配置详情 | ||
| */ | ||
| /** 获取当前配置信息 */ | ||
| getConfig() { | ||
@@ -462,14 +326,4 @@ const maxWorkerId = (1 << Number(this.workerIdBitLength)) - 1; | ||
| /** | ||
| * 验证 ID 是否为有效的 Snowflake ID | ||
| * | ||
| * @param {number|bigint|string} id - 要验证的 ID | ||
| * @param {boolean} [strictWorkerId=false] - 是否严格验证 workerId 必须匹配当前实例 | ||
| * @returns {boolean} ID 是否有效 | ||
| * | ||
| * @example | ||
| * const genid = new GenidOptimized({ workerId: 1 }); | ||
| * const id = genid.nextId(); | ||
| * genid.isValid(id); // true | ||
| * genid.isValid(12345); // false | ||
| * genid.isValid(id, true); // true (workerId 匹配) | ||
| * 验证 ID 是否为当前配置下合法的 Snowflake ID | ||
| * @param strictWorkerId - 为 true 时要求 workerId 匹配当前实例 | ||
| */ | ||
@@ -497,8 +351,3 @@ isValid(id, strictWorkerId = false) { | ||
| } | ||
| /** | ||
| * 将 ID 格式化为二进制字符串以便调试 | ||
| * | ||
| * @param {number|bigint|string} id - 要格式化的 ID | ||
| * @returns {string} 格式化的二进制表示 | ||
| */ | ||
| /** 将 ID 格式化为带标注的二进制字符串(调试用) */ | ||
| formatBinary(id) { | ||
@@ -521,4 +370,3 @@ const idBigInt = BigInt(id); | ||
| }; | ||
| //#endregion | ||
| export { GenidOptimized }; | ||
| export { GenidMethod, GenidOptimized }; |
+4
-4
| { | ||
| "name": "@cdlab996/genid", | ||
| "type": "module", | ||
| "version": "1.2.1", | ||
| "version": "1.3.0", | ||
| "description": "基于 Snowflake 算法的高性能分布式唯一 ID 生成器", | ||
@@ -50,7 +50,7 @@ "author": "wudi <wuchendi96@gmail.com>", | ||
| "devDependencies": { | ||
| "@biomejs/biome": "^2.3.14", | ||
| "@biomejs/biome": "^2.4.7", | ||
| "@types/node": "^25", | ||
| "tsdown": "^0.20.3", | ||
| "tsdown": "^0.21.4", | ||
| "typescript": "^5", | ||
| "vitest": "^4.0.18" | ||
| "vitest": "^4.1.0" | ||
| }, | ||
@@ -57,0 +57,0 @@ "publishConfig": { |
+141
-244
| # @cdlab996/genid | ||
| 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理,适用于分布式系统中的唯一标识生成需求。 | ||
| [](https://www.npmjs.com/package/@cdlab996/genid) | ||
| [](./LICENSE) | ||
| 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。 | ||
| ## 特性 | ||
| - 🚀 **漂移算法**:高并发场景下性能优异 | ||
| - 🔄 **时钟回拨处理**:优雅处理时钟回拨,不阻塞 ID 生成 | ||
| - ⚙️ **灵活配置**:支持自定义位长度分配 | ||
| - 📊 **性能监控**:内置统计和调试功能 | ||
| - ✅ **ID 验证**:验证 ID 的有效性,支持严格/宽松模式 | ||
| - **漂移算法** - 高并发场景下突破每毫秒序列号上限,性能更优 | ||
| - **时钟回拨处理** - 使用保留序列号优雅降级,不阻塞 ID 生成 | ||
| - **灵活配置** - 支持自定义时间戳、节点 ID、序列号的位长度分配 | ||
| - **ID 验证** - 支持严格/宽松模式校验 ID 有效性 | ||
| - **运行监控** - 内置统计、解析和二进制格式化调试工具 | ||
| ## 架构设计 | ||
| ## 安装 | ||
| ### 核心流程 | ||
| ```bash | ||
| # npm | ||
| npm install @cdlab996/genid | ||
| ```mermaid | ||
| graph TB | ||
| A[开始生成 ID] --> B{是否处于漂移状态?} | ||
| B -->|否| C[正常路径] | ||
| B -->|是| D[漂移路径] | ||
| C --> E{检测时钟} | ||
| E -->|时钟回拨| F[使用保留序列号 0-4] | ||
| E -->|时间前进| G[重置序列号] | ||
| E -->|同一毫秒| H{序列号是否溢出?} | ||
| H -->|否| I[序列号+1 正常生成] | ||
| H -->|是| J[进入漂移状态 时间戳+1] | ||
| D --> K{检测时间} | ||
| K -->|时间追上| L[退出漂移 恢复正常] | ||
| K -->|超过最大漂移| M[等待下一毫秒 退出漂移] | ||
| K -->|继续漂移| N{序列号是否溢出?} | ||
| N -->|否| O[使用当前序列号] | ||
| N -->|是| P[时间戳+1 重置序列号] | ||
| F --> Q[计算 ID] | ||
| G --> Q | ||
| I --> Q | ||
| J --> Q | ||
| L --> Q | ||
| M --> Q | ||
| O --> Q | ||
| P --> Q | ||
| Q --> R[更新统计] | ||
| R --> S[返回 ID] | ||
| # pnpm | ||
| pnpm add @cdlab996/genid | ||
| ``` | ||
| ### ID 结构(64-bit) | ||
| ``` | ||
| |------------ 时间戳 ------------|-- 工作节点 ID --|-- 序列号 --| | ||
| 42-52 bits 1-15 bits 3-21 bits | ||
| ``` | ||
| **位分配示例(默认配置):** | ||
| - 时间戳:52 bits(可用约 139 年) | ||
| - 工作节点 ID:6 bits(支持 64 个节点) | ||
| - 序列号:6 bits(每毫秒 59 个 ID,5-63) | ||
| **序列号分配:** | ||
| - `0-4`:保留用于时钟回拨 | ||
| - `5-maxSeqNumber`:正常使用 | ||
| ## 快速开始 | ||
@@ -81,143 +36,73 @@ | ||
| const id = genid.nextId() | ||
| console.log(id) // 123456789012345 | ||
| ``` | ||
| ## API 参考 | ||
| // 批量生成 | ||
| const ids = genid.nextBatch(1000) | ||
| ### 构造函数 | ||
| // 解析 ID | ||
| const info = genid.parse(id) | ||
| // => { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 } | ||
| ```typescript | ||
| new GenidOptimized(options: GenidOptions) | ||
| // 验证 ID | ||
| genid.isValid(id) // true | ||
| ``` | ||
| **配置选项** | ||
| ## API | ||
| | 参数 | 类型 | 必填 | 默认值 | 说明 | | ||
| |------|------|------|--------|------| | ||
| | `workerId` | number | ✅ | - | 工作节点 ID(范围:0 到 2^workerIdBitLength-1) | | ||
| | `method` | GenidMethod | ❌ | `DRIFT` | 算法类型:`DRIFT` 或 `TRADITIONAL` | | ||
| | `baseTime` | number | ❌ | `1577836800000` | 起始时间戳(毫秒,默认:2020-01-01) | | ||
| | `workerIdBitLength` | number | ❌ | `6` | 工作节点 ID 位数(1-15) | | ||
| | `seqBitLength` | number | ❌ | `6` | 序列号位数(3-21) | | ||
| | `maxSeqNumber` | number | ❌ | `2^seqBitLength-1` | 最大序列号 | | ||
| | `minSeqNumber` | number | ❌ | `5` | 最小序列号(0-4 保留用于时钟回拨) | | ||
| | `topOverCostCount` | number | ❌ | `2000` | 最大漂移次数 | | ||
| ### `new GenidOptimized(options)` | ||
| | 参数 | 类型 | 必填 | 默认值 | 说明 | | ||
| | ------------------- | ------------- | :---: | ------------------ | --------------------------------------------- | | ||
| | `workerId` | `number` | Yes | - | 工作节点 ID(0 ~ 2^workerIdBitLength-1) | | ||
| | `method` | `GenidMethod` | | `DRIFT` | 算法:`DRIFT`(漂移)或 `TRADITIONAL`(传统) | | ||
| | `baseTime` | `number` | | `1577836800000` | 起始时间戳,毫秒(默认 2020-01-01) | | ||
| | `workerIdBitLength` | `number` | | `6` | 节点 ID 位数(1-15) | | ||
| | `seqBitLength` | `number` | | `6` | 序列号位数(3-21) | | ||
| | `maxSeqNumber` | `number` | | `2^seqBitLength-1` | 最大序列号 | | ||
| | `minSeqNumber` | `number` | | `5` | 最小序列号(0-4 保留用于时钟回拨) | | ||
| | `topOverCostCount` | `number` | | `2000` | 最大漂移次数 | | ||
| ### 生成 ID | ||
| #### `nextId()` | ||
| 返回 Number 或 BigInt 类型的 ID(自动选择) | ||
| ```typescript | ||
| const id = genid.nextId() | ||
| genid.nextId() // 返回 number | bigint(自动选择) | ||
| genid.nextNumber() // 返回 number(超出安全整数范围抛错) | ||
| genid.nextBigId() // 返回 bigint | ||
| genid.nextBatch(100) // 批量生成 100 个 ID | ||
| genid.nextBatch(100, true) // 批量生成 100 个 BigInt ID | ||
| ``` | ||
| #### `nextNumber()` | ||
| ### 解析与验证 | ||
| 返回 Number 类型的 ID(超出安全范围会抛出错误) | ||
| ```typescript | ||
| const id = genid.nextNumber() | ||
| ``` | ||
| // 解析 ID 的组成部分 | ||
| genid.parse(id) | ||
| // => { timestamp: Date, timestampMs: number, workerId: number, sequence: number } | ||
| #### `nextBigId()` | ||
| // 宽松验证:检查 ID 格式是否有效 | ||
| genid.isValid(id) // true | ||
| genid.isValid(12345) // false | ||
| genid.isValid('invalid') // false | ||
| 返回 BigInt 类型的 ID | ||
| ```typescript | ||
| const id = genid.nextBigId() | ||
| // 严格验证:要求 workerId 匹配当前实例 | ||
| genid.isValid(id, true) // true(本实例生成的 ID) | ||
| genid.isValid(otherId, true) // false(其他实例生成的 ID) | ||
| ``` | ||
| #### `nextBatch(count, asBigInt?)` | ||
| 批量生成 ID | ||
| ```typescript | ||
| const ids = genid.nextBatch(100) // 生成 100 个 ID | ||
| const bigIds = genid.nextBatch(100, true) // 生成 100 个 BigInt ID | ||
| ``` | ||
| ### 解析 ID | ||
| #### `parse(id)` | ||
| 解析 ID,提取组成部分 | ||
| ```typescript | ||
| const info = genid.parse(id) | ||
| console.log(info) | ||
| // { | ||
| // timestamp: Date, // 生成时间 | ||
| // timestampMs: 1609459200000, | ||
| // workerId: 1, // 工作节点 ID | ||
| // sequence: 42 // 序列号 | ||
| // } | ||
| ``` | ||
| ### 验证 ID | ||
| #### `isValid(id, strictWorkerId?)` | ||
| 验证 ID 是否为有效的 Snowflake ID | ||
| **参数** | ||
| - `id` - 要验证的 ID(支持 Number、BigInt、String 类型) | ||
| - `strictWorkerId` - 可选,是否严格验证 workerId 必须匹配当前实例(默认:false) | ||
| **返回值** | ||
| - `boolean` - ID 是否有效 | ||
| **验证规则** | ||
| - ✅ ID 为正数 | ||
| - ✅ ID 在 64 位范围内 | ||
| - ✅ 时间戳在合理范围内(>= baseTime,<= 当前时间 + 1秒容差) | ||
| - ✅ workerId 在有效范围内(0 到 2^workerIdBitLength-1) | ||
| - ✅ 序列号在有效范围内(0 到 2^seqBitLength-1) | ||
| - ✅ 严格模式下:workerId 必须匹配当前实例 | ||
| ```typescript | ||
| const genid = new GenidOptimized({ workerId: 1 }) | ||
| const id = genid.nextId() | ||
| // 宽松模式:验证 ID 格式是否有效 | ||
| genid.isValid(id) // true | ||
| genid.isValid(12345) // false(无效的 ID) | ||
| genid.isValid(-1) // false(负数) | ||
| genid.isValid('invalid') // false(无效格式) | ||
| // 严格模式:验证 ID 是否由当前实例生成 | ||
| const genid2 = new GenidOptimized({ workerId: 2 }) | ||
| const id2 = genid2.nextId() | ||
| genid.isValid(id2) // true(宽松模式,其他实例的 ID 也有效) | ||
| genid.isValid(id2, true) // false(严格模式,workerId 不匹配) | ||
| genid.isValid(id, true) // true(严格模式,workerId 匹配) | ||
| ``` | ||
| ### 统计与配置 | ||
| #### `getStats()` | ||
| 获取生成器统计信息 | ||
| ```typescript | ||
| const stats = genid.getStats() | ||
| // { | ||
| // totalGenerated: 1000, // 总生成数量 | ||
| // overCostCount: 10, // 漂移次数 | ||
| // turnBackCount: 2, // 时钟回拨次数 | ||
| // uptimeMs: 60000, // 运行时间 | ||
| // avgPerSecond: 16, // 每秒平均生成量 | ||
| // currentState: 'NORMAL' // 当前状态 | ||
| // 获取运行统计 | ||
| genid.getStats() | ||
| // => { | ||
| // totalGenerated: 1000, | ||
| // overCostCount: 10, | ||
| // turnBackCount: 2, | ||
| // uptimeMs: 60000, | ||
| // avgPerSecond: 16, | ||
| // currentState: 'NORMAL' | 'OVER_COST' | ||
| // } | ||
| ``` | ||
| #### `getConfig()` | ||
| 获取配置信息 | ||
| ```typescript | ||
| const config = genid.getConfig() | ||
| // { | ||
| // 获取当前配置 | ||
| genid.getConfig() | ||
| // => { | ||
| // method: 'DRIFT', | ||
@@ -227,2 +112,3 @@ // workerId: 1, | ||
| // sequenceRange: '5-63', | ||
| // maxSequence: 63, | ||
| // idsPerMillisecond: 59, | ||
@@ -234,20 +120,11 @@ // baseTime: Date, | ||
| // } | ||
| ``` | ||
| #### `resetStats()` | ||
| 重置统计数据 | ||
| ```typescript | ||
| // 重置统计 | ||
| genid.resetStats() | ||
| ``` | ||
| ### 调试工具 | ||
| ### 调试 | ||
| #### `formatBinary(id)` | ||
| 格式化 ID 为二进制字符串 | ||
| ```typescript | ||
| console.log(genid.formatBinary(id)) | ||
| genid.formatBinary(id) | ||
| // ID: 123456789012345 | ||
@@ -262,19 +139,7 @@ // Binary (64-bit): | ||
| ### 基础用法 | ||
| ### 自定义位分配 | ||
| ```typescript | ||
| const genid = new GenidOptimized({ | ||
| workerId: 1 | ||
| }) | ||
| import { GenidOptimized, GenidMethod } from '@cdlab996/genid' | ||
| // 生成单个 ID | ||
| const id1 = genid.nextId() | ||
| // 批量生成 | ||
| const ids = genid.nextBatch(1000) | ||
| ``` | ||
| ### 自定义配置 | ||
| ```typescript | ||
| const genid = new GenidOptimized({ | ||
@@ -284,40 +149,28 @@ workerId: 1, | ||
| baseTime: new Date('2024-01-01').valueOf(), | ||
| workerIdBitLength: 10, // 支持 1024 个节点 | ||
| seqBitLength: 12, // 每毫秒 4096 个 ID | ||
| topOverCostCount: 5000 | ||
| workerIdBitLength: 10, // 支持 1024 个节点 | ||
| seqBitLength: 12, // 每毫秒 4096 个 ID | ||
| topOverCostCount: 5000, | ||
| }) | ||
| ``` | ||
| ### 验证 ID | ||
| ### 验证外部 ID | ||
| ```typescript | ||
| const genid = new GenidOptimized({ workerId: 1 }) | ||
| // 生成并验证 ID | ||
| const id = genid.nextId() | ||
| if (genid.isValid(id)) { | ||
| console.log('ID 有效') | ||
| } | ||
| // 验证外部 ID(例如从数据库或 API 获取的 ID) | ||
| // 验证从数据库或 API 获取的 ID | ||
| const externalId = '123456789012345' | ||
| if (genid.isValid(externalId)) { | ||
| const info = genid.parse(externalId) | ||
| console.log('ID 有效,解析结果:', info) | ||
| console.log('生成时间:', info.timestamp) | ||
| console.log('来自节点:', info.workerId) | ||
| } else { | ||
| console.error('ID 无效') | ||
| console.error('无效 ID') | ||
| } | ||
| // 严格验证(只接受当前实例生成的 ID) | ||
| const isMyId = genid.isValid(id, true) | ||
| ``` | ||
| ### 监控性能 | ||
| ### 性能监控 | ||
| ```typescript | ||
| // 定期检查统计信息 | ||
| setInterval(() => { | ||
| const stats = genid.getStats() | ||
| console.log(`生成速率: ${stats.avgPerSecond} ID/秒`) | ||
| console.log(`漂移次数: ${stats.overCostCount}`) | ||
| console.log(`速率: ${stats.avgPerSecond} ID/s | 漂移: ${stats.overCostCount} | 回拨: ${stats.turnBackCount}`) | ||
| }, 10000) | ||
@@ -328,33 +181,77 @@ ``` | ||
| ### DRIFT(漂移模式,推荐) | ||
| | 模式 | 说明 | 适用场景 | | ||
| | ----------------- | ---------------------------------------- | -------------------- | | ||
| | **DRIFT**(默认) | 序列号耗尽时借用未来时间戳,避免等待 | 高频 ID 生成、高并发 | | ||
| | **TRADITIONAL** | 严格按时间戳递增,序列号耗尽等待下一毫秒 | 对时间顺序严格要求 | | ||
| - 高并发下性能更好 | ||
| - 允许时间戳漂移以避免等待 | ||
| - 适合高频 ID 生成场景 | ||
| ## 架构 | ||
| ### TRADITIONAL(传统模式) | ||
| ### ID 结构(64-bit) | ||
| - 严格按时间戳递增 | ||
| - 序列号耗尽时等待下一毫秒 | ||
| - 适合对时间顺序要求严格的场景 | ||
| ``` | ||
| |------------ 时间戳 ------------|-- 工作节点 ID --|-- 序列号 --| | ||
| 42-52 bits 1-15 bits 3-21 bits | ||
| ``` | ||
| 默认配置:时间戳 52 bits(约 139 年)| 节点 ID 6 bits(64 个节点)| 序列号 6 bits(每毫秒 59 个 ID) | ||
| 序列号 `0-4` 保留用于时钟回拨,正常使用从 `5` 开始。 | ||
| ### 核心流程 | ||
| ```mermaid | ||
| graph TB | ||
| A[开始生成 ID] --> B{是否处于漂移状态?} | ||
| B -->|否| C[正常路径] | ||
| B -->|是| D[漂移路径] | ||
| C --> E{检测时钟} | ||
| E -->|时钟回拨| F[使用保留序列号 0-4] | ||
| E -->|时间前进| G[重置序列号] | ||
| E -->|同一毫秒| H{序列号是否溢出?} | ||
| H -->|否| I[序列号+1 正常生成] | ||
| H -->|是| J[进入漂移状态 时间戳+1] | ||
| D --> K{检测时间} | ||
| K -->|时间追上| L[退出漂移 恢复正常] | ||
| K -->|超过最大漂移| M[等待下一毫秒 退出漂移] | ||
| K -->|继续漂移| N{序列号是否溢出?} | ||
| N -->|否| O[使用当前序列号] | ||
| N -->|是| P[时间戳+1 重置序列号] | ||
| F --> Q[计算 ID] | ||
| G --> Q | ||
| I --> Q | ||
| J --> Q | ||
| L --> Q | ||
| M --> Q | ||
| O --> Q | ||
| P --> Q | ||
| Q --> R[更新统计] | ||
| R --> S[返回 ID] | ||
| ``` | ||
| ## 注意事项 | ||
| ⚠️ **重要提示** | ||
| - 每个 Worker/进程必须使用**不同的 workerId** | ||
| - 实例**不是线程安全的**,不要跨线程共享 | ||
| - 实例**非线程安全**,不要跨线程共享 | ||
| - `workerIdBitLength + seqBitLength` 不能超过 22 | ||
| - 序列号 0-4 保留用于时钟回拨处理 | ||
| - JavaScript 安全整数范围:`-(2^53-1)` 到 `2^53-1` | ||
| - 超出 JavaScript 安全整数范围(2^53-1)时,使用 `nextBigId()` 或 `nextId()`(自动返回 BigInt) | ||
| ## 性能指标 | ||
| ## 性能 | ||
| - 单实例吞吐量:> 50,000 ID/秒 | ||
| - 默认配置下每毫秒可生成:59 个唯一 ID | ||
| - 支持的最大节点数:2^workerIdBitLength(默认 64 个) | ||
| - 时间戳可用时长:约 139 年(52 bits,从 baseTime 起算) | ||
| | 指标 | 数值 | | ||
| | -------------------------- | ------------- | | ||
| | 单实例吞吐量 | > 50,000 ID/s | | ||
| | 每毫秒生成量(默认配置) | 59 个 | | ||
| | 最大节点数(默认配置) | 64 个 | | ||
| | 时间戳可用时长(默认配置) | ~139 年 | | ||
| ## 📜 License | ||
| ## License | ||
| [MIT](./LICENSE) License © 2025-PRESENT [wudi](https://github.com/WuChenDi) |
49023
-25.08%706
-29.61%252
-29.01%