新建 SnowflakeIdGenerate.ts
// src/utils/Snowflake.ts
/**
* Snowflake主鍵生成算法
* 完整的算法是生成的ID長(zhǎng)度為20位
* 但是由于js最大值9007199254740991,再多就會(huì)溢出,再多要特殊處理。
* 所以這里設(shè)置長(zhǎng)度為16位id。將數(shù)據(jù)中心位調(diào)小到1位铁追,將服務(wù)器位調(diào)小到1位,將序列位調(diào)小到10位
* 這意味著最多支持兩個(gè)數(shù)據(jù)中心,每個(gè)數(shù)據(jù)中心最多支持兩臺(tái)服務(wù)器
*/
export class SnowflakeIdGenerate {
private twepoch = 0;
private workerIdBits = 1;
private dataCenterIdBits = 1;
private maxWrokerId = -1 ^ (-1 << this.workerIdBits); // 值為:1
private maxDataCenterId = -1 ^ (-1 << this.dataCenterIdBits); // 值為:1
private sequenceBits = 10;
private workerIdShift = this.sequenceBits; // 值為:10
private dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值為:11
// private timestampLeftShift =
// this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值為:12
private sequenceMask = -1 ^ (-1 << this.sequenceBits); // 值為:4095
private lastTimestamp = -1;
private workerId = 1; //設(shè)置默認(rèn)值,從環(huán)境變量取
private dataCenterId = 1;
private sequence = 0;
constructor(_workerId = 0, _dataCenterId = 0, _sequence = 0) {
if (this.workerId > this.maxWrokerId || this.workerId < 0) {
throw new Error('config.worker_id must max than 0 and small than maxWrokerId-[' + this.maxWrokerId + ']');
}
if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0) {
throw new Error(
'config.data_center_id must max than 0 and small than maxDataCenterId-[' + this.maxDataCenterId + ']',
);
}
this.workerId = _workerId;
this.dataCenterId = _dataCenterId;
this.sequence = _sequence;
}
private timeGen = (): number => {
return Date.now();
};
private tilNextMillis = (lastTimestamp): number => {
let timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
};
private nextId = (): number => {
let timestamp: number = this.timeGen();
if (timestamp < this.lastTimestamp) {
throw new Error('Clock moved backwards. Refusing to generate id for ' + (this.lastTimestamp - timestamp));
}
if (this.lastTimestamp === timestamp) {
this.sequence = (this.sequence + 1) & this.sequenceMask;
if (this.sequence === 0) {
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
this.lastTimestamp = timestamp;
// js 最大值 9007199254740991麦撵,再多就會(huì)溢出
// 超過(guò) 32 位長(zhǎng)度,做位運(yùn)算會(huì)溢出溃肪,變成負(fù)數(shù)免胃,所以這里直接做乘法,乘法會(huì)擴(kuò)大存儲(chǔ)
const timestampPos = (timestamp - this.twepoch) * 4096;
const dataCenterPos = this.dataCenterId << this.dataCenterIdShift;
const workerPos = this.workerId << this.workerIdShift;
return timestampPos + dataCenterPos + workerPos + this.sequence;
};
generate = (): number => {
return this.nextId();
};
}
使用
const idGenerate: SnowflakeIdGenerate = new SnowflakeIdGenerate();
console.log(idGenerate.generate());