现在好多的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>

  原生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>

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

Snowflake(雪花算法)的JavaScript实现的更多相关文章

  1. .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块

    .Net Core ORM选择之路,哪个才适合你   因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...

  2. 分布式Snowflake雪花算法

    前言 项目中主键ID生成方式比较多,但是哪种方式更能提高的我们的工作效率.项目质量.代码实用性以及健壮性呢,下面作了一下比较,目前雪花算法的优点还是很明显的. 优缺点比较 UUID(缺点:太长.没法排 ...

  3. 分布式ID生成器 snowflake(雪花)算法

    在springboot的启动类中引入 @Bean public IdWorker idWorkker(){ return new IdWorker(1, 1); } 在代码中调用 @Autowired ...

  4. 说起分布式自增ID只知道UUID?SnowFlake(雪花)算法了解一下(Python3.0实现)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_155 但凡说起分布式系统,我们肯定会对一些海量级的业务进行分拆,比如:用户表,订单表.因为数据量巨大一张表完全无法支撑,就会对其进 ...

  5. 分布式主键解决方案之--Snowflake雪花算法

    0--前言 对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键,优点是方便又能解决问题,缺点是插入时因为UUID/G ...

  6. Go语言实现Snowflake雪花算法

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/527 每次放长假的在家里的时候,总想找点简单的例子来看看实现原理,这 ...

  7. snowflake 雪花算法 分布式实现全局id生成

    snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID. 这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案 ...

  8. 分布式系统为什么不用自增id,要用雪花算法生成id???

    1.为什么数据库id自增和uuid不适合分布式id id自增:当数据量庞大时,在数据库分库分表后,数据库自增id不能满足唯一id来标识数据:因为每个表都按自己节奏自增,会造成id冲突,无法满足需求.  ...

  9. 雪花算法及微服务集群唯一ID解决方案

    雪花算法(SnowFlake) 简介 现在的服务基本是分布式.微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性. 对于 MySQL 而言,一个表中的主键 ...

随机推荐

  1. 游戏UI框架设计(6): 消息传递中心

    游戏UI框架设计(6) --消息传递中心 最近一直忙于一个益智类游戏的研发工作,所以博客有段时间没有更新了.经过朋友的督促,决定这两天立刻完成最后的两篇博客讲解(UI框架).说起“消息传递中心”,或者 ...

  2. Asp.NETCore轻松学系列阅读指引目录

    前言 耗时两个多月,坚持写这个入门系列文章,就是想给后来者更好更快的上手体验,这个系列可以说是从入门到进阶,适合没有 .NETCore 编程经验到小白同学,也适合从 .NET Framework 迁移 ...

  3. java之servlet入门操作教程一续

    本节主要是在java之servlet入门操作教程一  的基础上使用myeclipse实现自动部署的功能 准备: java之servlet入门操作教程一 中完成myFirstServlet项目的创建: ...

  4. Fundebug微信小程序错误监控插件更新至1.1.0,新增test()与notifyHttpError()方法

    摘要: 1.1.0新增fundebug.test()和fundebug.notifyHttpError()方法,同时大小压缩至15K. Fundebug是专业的小程序BUG监控服务,可以第一时间为您捕 ...

  5. CesiumJS 添加会动的GIF

    由于Cesium使用canvas渲染,如果使用billboard等加载gif图片只能渲染第一帧,导致动图不动.在Cesium的官方示例中找到一段代码可将HTML元素渲染到地图上,将gif以html元素 ...

  6. Ambari安装及自定义service初步实现

    Ambari安装 1 Ambari简介 Apache Ambari项目的目的是通过开发软件来配置.监控和管理hadoop集群,以使hadoop的管理更加简单.同时,ambari也提供了一个基于它自身R ...

  7. JS的常用正则表达式 验证密码(转载自用)

    JS的正则表达式 强:字母+数字+特殊字符   ^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^& ...

  8. 性能测试工具 wrk 使用教程

    文章首发自个人微信公众号:小哈学Java 个人网站地址:https://www.exception.site/wrk 被面试官经常问到之前开发的系统接口 QPS 能达到多少,经常给不出一个数值,支支吾 ...

  9. HandlerInterceptor里@Autowired对象为空的解决方法

    That's because Spring isn't managing your PagePopulationInterceptor instance. You are creating it yo ...

  10. [Leetcode]450. Delete Node in a BST

    Given a root node reference of a BST and a key, delete the node with the given key in the BST. Retur ...