便利贴--34{nodejs,雪花算法,计算设备不同,唯一id,-其实可以自己拿时间轴去自己建个}

便利贴--34{nodejs,雪花算法,计算设备不同,唯一id,-其实可以自己拿时间轴去自己建个}

直接上代码

/**
 * 雪花 ID 生成器
 * Date: 2020年9月25日14:20:21
 * Version: 1.0.0
 * A function for converting hex <-> dec w/o loss of precision.
 * By Dan Vanderkam http://www.danvk.org/hex2dec.html
 * @description js Number最大长度不超过17位,否则会出现精度丢失的问题
 */
class SnowflakeID {
    constructor(options) {
        options = options || {};
        this.seq = 0;
        //机器id或任何随机数。如果您是在分布式系统中生成id,强烈建议您提供一个适合不同机器的mid。
        this.mid = (options.mid || 1) % 1023;
        //这是一个时间偏移量,它将从当前时间中减去以获得id的前42位。这将有助于生成更小的id。
        this.offset = options.offset || (new Date().getFullYear() - 1970) * 31536000 * 1000;
        this.lastTime = 0;
    }

    generate() {
        const time = Date.now();
        const bTime = (time - this.offset).toString(2);
        // get the sequence number
        if (this.lastTime == time) {
            this.seq++;
            if (this.seq > 4095) {
                this.seq = 0;
                // make system wait till time is been shifted by one millisecond
                while (Date.now() <= time) {}
            }
        } else {
            this.seq = 0;
        }

        this.lastTime = time;

        let bSeq = this.seq.toString(2);
        let bMid = this.mid.toString(2);

        // create sequence binary bit
        while (bSeq.length < 12) bSeq = '0' + bSeq;

        while (bMid.length < 10) bMid = '0' + bMid;

        const bid = bTime + bMid + bSeq;
        let id = '';
        for (let i = bid.length; i > 0; i -= 4) {
            id = parseInt(bid.substring(i - 4, i), 2).toString(16) + id;
        }
        return this.hexToDec(id);
    }

    add(x, y, base) {
        let z = [];
        let n = Math.max(x.length, y.length);
        let carry = 0;
        let i = 0;
        while (i < n || carry) {
            let xi = i < x.length ? x[i] : 0;
            let yi = i < y.length ? y[i] : 0;
            let zi = carry + xi + yi;
            z.push(zi % base);
            carry = Math.floor(zi / base);
            i++;
        }
        return z;
    }

    /**
     * 乘以数字
     * @param {*} num
     * @param {*} x
     * @param {*} base
     */
    multiplyByNumber(num, x, base) {
        if (num < 0) return null;
        if (num == 0) return [];

        let result = [];
        let power = x;
        while (true) {
            if (num & 1) {
                result = this.add(result, power, base);
            }
            num = num >> 1;
            if (num === 0) break;
            power = this.add(power, power, base);
        }

        return result;
    }

    /**
     * 解析为数组
     * @param {*} str
     * @param {*} base
     */
    parseToDigitsArray(str, base) {
        let digits = str.split('');
        let ary = [];
        for (let i = digits.length - 1; i >= 0; i--) {
            let n = parseInt(digits[i], base);
            if (isNaN(n)) return null;
            ary.push(n);
        }
        return ary;
    }

    /**
     * 转换
     * @param {*} str
     * @param {*} fromBase
     * @param {*} toBase
     */
    convertBase(str, fromBase, toBase, legnth) {
        let digits = this.parseToDigitsArray(str, fromBase);
        if (digits === null) return null;
        let outArray = [];
        let power = [1];
        for (let i = 0; i < digits.length; i++) {
            // inletiant: at this point, fromBase^i = power
            if (digits[i]) {
                outArray = this.add(
                    outArray,
                    this.multiplyByNumber(digits[i], power, toBase),
                    toBase
                );
            }
            power = this.multiplyByNumber(fromBase, power, toBase);
        }
        let out = '';
        //设置了这里-3会返回16位的字符,如果是设置为outArray.length - 1 会返回18位的字符
        for (let i = outArray.length - 3; i >= 0; i--) {
            out += outArray[i].toString(toBase);
        }
        return out;
    }

    /**
     * 16进制=> 10进制
     * @param {*} hexStr
     */
    hexToDec(hexStr) {
        if (hexStr.substring(0, 2) === '0x') hexStr = hexStr.substring(2);
        hexStr = hexStr.toLowerCase();
        return this.convertBase(hexStr, 16, 10);
    }
}

//下面是测试代码部分,不需要的可以直接移除
const snid = new SnowflakeID({
    mid: +new Date()	
});
let id = snid.generate();
console.log(id, id.length);
let arr = [];
for (let index = 0; index < 10000; index++) {
    id = snid.generate();
    console.log(id);
    arr.push(snid.generate(), +new Date());
}
//测试是否会有重复的id,目前的测试情况来看,不会有重复的
// console.log(arr, arr.length, Array.from(new Set(arr)).length);
module.exports = SnowflakeID;`

再次感谢博主狼丶宇先森做的整理

原文连接: link.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值