UUID生成策略/算法JavaScript / Typescript
UUID生成策略/算法(JavaScript / Typescript)
-
我只是想简单的生成一些UUID,不想引入一堆库,所以最后设计了一个简单的UUID生成策略。
-
下面的UUID生成方法是依据时间戳、随机数、count计数器三个输入因子生成的,能保证本地的UUID是不会重复的,但是在多用户端环境下有非常非常低的概率出现重复。
-
多用户端场景UUID有可能重复的极端场景,需要满足以下两个前提条件:
- 两个用户端在同一毫秒内完成了此代码的初始化(获得了相同的时间戳)。
- 两个用户生成的随机数相同(理论上相同的概率是一百亿分之一)。
实现代码(JavaScript / Typescript):
// UUID中允许出现的基本字符;
const baseChar: string[] = (() => {
const array: string[] = [];
// 将数字0-9加入到 baseChar 中
for (let i = 0; i < 10; i ) {
array.push(i.toString(10));
}
// 将小写字母a-z加入到 baseChar 中
for (let i = 0; i < 26; i ) {
array.push(String.fromCharCode('a'.charCodeAt(0) i));
}
// 将大写字母A-Z加入到 baseChar 中
for (let i = 0; i < 26; i ) {
array.push(String.fromCharCode('A'.charCodeAt(0) i));
}
return array;
})();
// 进制转换/数字转字符
function scaleTransition(value: number, base = baseChar): string {
if (value < 0) {
throw new Error('scaleTransition Error, value < 0');
}
if (value === 0) {
return base[0];
}
const radix = base.length;
let result = '';
let resValue = value;
while (resValue > 0) {
result = base[resValue % radix] result;
resValue = Math.floor(resValue / radix);
}
return result;
}
// UUID参数集合, 使用 count 能保证在本地环境中UUID绝对不会重复.
const UuidObject: Record<string, { prefix: string; count: number }> = {};
// 生成随机的UUID
export default function createUUID(prefix = '') {
let uuidObject = UuidObject[prefix];
if (uuidObject === undefined) {
const str = `${scaleTransition(Date.now())}-${scaleTransition(
Math.floor(Math.random() * 10000000000),
)}-`;
if (prefix) {
uuidObject = {
prefix: `${prefix}-${str}`,
count: 0,
};
} else {
uuidObject = {
prefix: str,
count: 0,
};
}
UuidObject[prefix] = uuidObject;
}
return uuidObject.prefix scaleTransition(uuidObject.count );
}
- 这里的baseChar中包含的是UUID中允许出现的字符。
- scaleTransition会将传入的value进行“进制转换”。
- 总得来说,baseChar其中包含的字符越多,最后生成的UUID长度越短。
进阶版,加入服务端前缀与MD5散列
import MD5 from 'md5';
// UUID中的分隔符
const splitChar = '.';
// UUID中允许出现的基本字符;
const baseChar: string[] = (() => {
const array: string[] = [];
// 将数字0-9加入到 baseChar 中
for (let i = 0; i < 10; i ) {
array.push(i.toString(10));
}
// 将小写字母a-z加入到 baseChar 中
for (let i = 0; i < 26; i ) {
array.push(String.fromCharCode('a'.charCodeAt(0) i));
}
// 将大写字母A-Z加入到 baseChar 中
for (let i = 0; i < 26; i ) {
array.push(String.fromCharCode('A'.charCodeAt(0) i));
}
// 加入一些其它的ASCII中的打印字符(尽量对URL或者JSON友好)
array.push('*', ' ', '-', '<', '=', '>');
array.push('(', ')', '[', ']', '{', '}', '|');
array.push('!', '$', '%', ':', ';', '@', '^', '_', '~');
return array;
})();
// 进制转换/数字转字符
function scaleTransition(value: number | bigint, base = baseChar): string {
if (value < 0) {
throw new Error('scaleTransition Error, value < 0');
}
if (value === 0) {
return base[0];
}
if (typeof value === 'bigint') {
const radix = BigInt(base.length);
let result = '';
let resValue = value;
while (resValue > 0) {
result = base[Number(resValue % radix)] result;
resValue /= radix;
}
return result;
} else {
const radix = base.length;
let result = '';
let resValue = value;
while (resValue > 0) {
result = base[resValue % radix] result;
resValue = Math.floor(resValue / radix);
}
return result;
}
}
function getPrefix(): string {
// TODO 从服务端UUID前缀, 来避免多用户端生成的uuid出现重复, (如果获取失败,则使用时间戳来兜底)
return String(Date.now());
}
// UUID参数集合, 使用 count 能保证在本地环境中UUID绝对不会重复.
const UuidObject: Record<string, { prefix: string; count: number }> = {};
function getUuidInfo(prefix: string): { prefix: string; count: number } {
let uuidObject = UuidObject[prefix];
if (uuidObject === undefined) {
// 先使用MD5将 getPrefix 散列成为一个32位长度的16进制字符串, 再将其转换为bigInt数值, 最后使用scaleTransition转换来压缩长度
const str1 = scaleTransition(BigInt(`0x${MD5(getPrefix())}`));
// MD5散列理论上存在碰撞的可能性, 可以在加入一个一亿以内的随机数降低在散列发生碰撞时生成UUID重复的可能性
const str2 = scaleTransition(Math.floor(Math.random() * 100000000));
if (prefix) {
uuidObject = {
prefix: prefix splitChar str1 splitChar str2 splitChar,
count: 0,
};
} else {
uuidObject = {
prefix: str1 splitChar str2 splitChar,
count: 0,
};
}
UuidObject[prefix] = uuidObject;
}
return uuidObject;
}
// 生成随机的UUID
export default function createUUID(prefix = '') {
const uuidObject = getUuidInfo(prefix);
return uuidObject.prefix scaleTransition(uuidObject.count );
}
// for (let i = 0; i < 10; i ) {
// console.log(createUUID());
// }
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgghhah
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13