• Snowflake(雪花算法)的JavaScript实现


      现在好多的ID都是服务器端生成的,当然JS也可以生成GUID或者UUID之类的,但是如果想要有序……这时就想到了雪花算法,但是都知道JS中Number的最大值为Number.MAX_SAFE_INTEGER:9007199254740991。在雪花算法中,有的操作在JS中会溢出。不过还好,网上有好多BigInt的类库,例如本例使用的:http://peterolson.github.io/BigInteger.js/ ,还有就是chrome67 原生支持BigInt类型,这是个好消息……

      参考文章: 理解分布式id生成算法SnowFlake

      类库:http://peterolson.github.io/BigInteger.js/

      CDN:https://cdnjs.com/

      记录一下代码

      类库方式实现:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    
    <body>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.32/BigInteger.min.js"></script>
        <!-- <script src="http://peterolson.github.com/BigInteger.js/BigInteger.min.js"></script> -->
        <script>
            var Snowflake = /** @class */ (function() {
                function Snowflake(_workerId, _dataCenterId, _sequence) {
                    // this.twepoch = 1288834974657;
                    this.twepoch = 0;
                    this.workerIdBits = 5;
                    this.dataCenterIdBits = 5;
                    this.maxWrokerId = -1 ^ (-1 << this.workerIdBits); // 值为:31
                    this.maxDataCenterId = -1 ^ (-1 << this.dataCenterIdBits); // 值为:31
                    this.sequenceBits = 12;
                    this.workerIdShift = this.sequenceBits; // 值为:12
                    this.dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值为:17
                    this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值为:22
                    this.sequenceMask = -1 ^ (-1 << this.sequenceBits); // 值为:4095
                    this.lastTimestamp = -1;
                    //设置默认值,从环境变量取
                    this.workerId = 1;
                    this.dataCenterId = 1;
                    this.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;
                }
                Snowflake.prototype.tilNextMillis = function(lastTimestamp) {
                    var timestamp = this.timeGen();
                    while (timestamp <= lastTimestamp) {
                        timestamp = this.timeGen();
                    }
                    return timestamp;
                };
                Snowflake.prototype.timeGen = function() {
                    //new Date().getTime() === Date.now()
                    return Date.now();
                };
                Snowflake.prototype.nextId = function() {
                    var timestamp = 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;
                    var shiftNum = (this.dataCenterId << this.dataCenterIdShift) |
                        (this.workerId << this.workerIdShift) |
                        this.sequence; // dataCenterId:1,workerId:1,sequence:0  shiftNum:135168
                    var nfirst = new bigInt(String(timestamp - this.twepoch), 10);
                    nfirst = nfirst.shiftLeft(this.timestampLeftShift);
                    var nnextId = nfirst.or(new bigInt(String(shiftNum), 10)).toString(10);
                    return nnextId;
                };
                return Snowflake;
            }());
            var tempSnowflake = new Snowflake(1, 1, 0);
            var tempIds = [];
            console.time();
            for (var i = 0; i < 10000; i++) {
                var tempId = tempSnowflake.nextId();
                console.log(tempId);
                if (tempIds.indexOf(tempId) < 0) {
                    tempIds.push(tempId);
                }
            }
            console.log(tempIds.length);
            console.timeEnd();
        </script>
    </body>
    
    </html>
    View Code

      原生BigInt实现:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    
    <body>
        <script>
            var Snowflake = /** @class */ (function() {
                function Snowflake(_workerId, _dataCenterId, _sequence) {
                    this.twepoch = 1288834974657n;
                    //this.twepoch = 0n;
                    this.workerIdBits = 5n;
                    this.dataCenterIdBits = 5n;
                    this.maxWrokerId = -1n ^ (-1n << this.workerIdBits); // 值为:31
                    this.maxDataCenterId = -1n ^ (-1n << this.dataCenterIdBits); // 值为:31
                    this.sequenceBits = 12n;
                    this.workerIdShift = this.sequenceBits; // 值为:12
                    this.dataCenterIdShift = this.sequenceBits + this.workerIdBits; // 值为:17
                    this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.dataCenterIdBits; // 值为:22
                    this.sequenceMask = -1n ^ (-1n << this.sequenceBits); // 值为:4095
                    this.lastTimestamp = -1n;
                    //设置默认值,从环境变量取
                    this.workerId = 1n;
                    this.dataCenterId = 1n;
                    this.sequence = 0n;
                    if (this.workerId > this.maxWrokerId || this.workerId < 0) {
                        throw new Error('_workerId must max than 0 and small than maxWrokerId-[' + this.maxWrokerId + ']');
                    }
                    if (this.dataCenterId > this.maxDataCenterId || this.dataCenterId < 0) {
                        throw new Error('_dataCenterId must max than 0 and small than maxDataCenterId-[' + this.maxDataCenterId + ']');
                    }
    
                    this.workerId = BigInt(_workerId);
                    this.dataCenterId = BigInt(_dataCenterId);
                    this.sequence = BigInt(_sequence);
                }
                Snowflake.prototype.tilNextMillis = function(lastTimestamp) {
                    var timestamp = this.timeGen();
                    while (timestamp <= lastTimestamp) {
                        timestamp = this.timeGen();
                    }
                    return BigInt(timestamp);
                };
                Snowflake.prototype.timeGen = function() {
                    return BigInt(Date.now());
                };
                Snowflake.prototype.nextId = function() {
                    var timestamp = 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 + 1n) & this.sequenceMask;
                        if (this.sequence === 0n) {
                            timestamp = this.tilNextMillis(this.lastTimestamp);
                        }
                    } else {
                        this.sequence = 0n;
                    }
                    this.lastTimestamp = timestamp;
                    return ((timestamp - this.twepoch) << this.timestampLeftShift) |
                        (this.dataCenterId << this.dataCenterIdShift) |
                        (this.workerId << this.workerIdShift) |
                        this.sequence;
                };
                return Snowflake;
            }());
            console.time();
            var tempSnowflake = new Snowflake(1n, 1n, 0n);
            var tempIds = [];
            for (var i = 0; i < 10000; i++) {
                var tempId = tempSnowflake.nextId();
                console.log(tempId);
                if (tempIds.indexOf(tempId) < 0) {
                    tempIds.push(tempId);
                }
            }
            console.log(tempIds.length);
            console.timeEnd();
        </script>
    </body>
    
    </html>
    View Code

      好像原生效果更好一些,到此结束。

  • 相关阅读:
    tslib編译和安装
    Web服务器的工作原理
    激励一生的六个经典故事
    VS2010中创建安装项目
    vue中img标签图片 加载时 与 加载失败 的处理方法
    Vue函数式组件的应用
    深入浅出Object.defineProperty()
    重学Git(一)
    backgroundblendmode
    箭头流程图前端实现
  • 原文地址:https://www.cnblogs.com/du-blog/p/9250660.html
Copyright © 2020-2023  润新知