在聊天模块工作时,初始消息唯一标识为msgId,可以满足业务量较小时的需求,毫秒级的唯一冲突很难出现.但是当用户数量增加时,这种时间戳的方案显然不可行。因此,有必要引入一种新的前端解决方案来生成唯一标识符。除了时间戳,我在公司的其他前端项目中也发现了一些其他的前端唯一标识实现,所以在此记录一下。时间戳唯一性差(目前应用于聊天消息的唯一标识)随机字符串唯一性强(目前应用于OSS存储文件的唯一标识名)uuid唯一性极强(有待介绍更唯一的解决方案)什么是RFC4122节点-什么是uuidnode-uuid?uuid的v1、v3、v4、v5是什么意思?现有项目uuid应用分析node-uuid项目实践总结与思考时间戳应用于聊天模块的msgId,采用时间戳的形式。this.message.msgId=`${+newDate()}`;//虽然说"1568689340401"唯一性差,但是到目前为止还没有因为唯一性差导致的大问题。随机字符串函数randomString(length){constchars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-';让结果='';for(leti=length;i>0;--i){result+=chars[Math.rand(()*chars.length)];}returnresult;}如果输入的长度是64,那么这个随机数算法会生成0~9,a~z,A~Z,-=_中的64乘以64的五分之一平方的随机字符串,64次3.940200619639448e+115,亿级才1.0e+10,这个数已经是庞大的离谱,唯一性已经很强了。唯一性会随着长度的减小而降低,所以在文件名过长时调整文件名长度时要特别注意。uuidnode-uuid是一个基于RFC4122加密算法的nodejs实现,在现代前端项目中可以直接引用。UUID的全写是UniversallyUniqueIDentifier,可以理解为全球唯一的标识码。(引入uuid后就不用担心手头项目前端证书不唯一了,因为UUID是全球唯一的。)RFC4122是什么,看一个官方就基本明白了RFC4122摘要。摘要本规范为UUID(通用唯一标识符)定义了统一资源名称命名空间,也称为GUID(全局唯一标识符)。UUID长度为128位,可以保证跨空间和时间的唯一性。UUID最初用于Apollo网络计算系统,后来用于开放软件基金会(OSF)的分布式计算环境(DCE),然后用于MicrosoftWindows平台。此规范源自DCE规范,并获得OSF(现称为TheOpenGroup)的许可。来自早期版本的DCE规范的信息已合并到本文档中。可提炼出以下知识点:本规范定义了UUID(UniversallyUniqueIDentifier)的统一资源名称命名空间,也可称为GUID(GlobalUniqueIDentifier)。UUID的长度为128位,可以保证空间和时间维度上的唯一性。UUID最早的应用是在阿波罗网络计算系统上,后来在开源软件基金会(OSF)和分布式计算环境(DCE)上,再后来在微软的Windows平台上。该规范源自OSF许可下的DCE规范。(OSF指的是OpenGroup)DCE规范的早期版本的内容被合并到本文档中。从上面对RFC4122的描述可以看出,RFC4122其实是一个UUID规范,最初诞生于ApolloComputer,一直沿用至今。基于此规范,有多种语言版本。从github上,我找到了一个基于RFC4122实现的UUID的repo,有多种语言。语言仓库名称地址phpuuidhttps://github.com/ramsey/uuidnodejsnode-uuidhttps://github.com/kelektiv/n...gogo.uuidhttps://github.com/satori/go....rustuuidhttps:///github.com/uuid-rs/uuidpythonshortuuidhttps://github.com/skorokitha...objective-cFCUUIDhttps://github.com/fabiocacca...node-uuidNode-uuid是一个符合commonjs规范的nodejs实现而RFC4122的UUID支持版本1、3、4、5。多个版本的UUID是跨平台的,在浏览器端和节点端都可以使用。可加密——必要时可使用随机数API进行加密。增强的安全性。零依赖,纯自给packageuuid的v1,v3,v4,v5是什么意思?v1timestamp(时间戳)uuid.v1(options,buffer,offset)选项包括node、clockseq、msecs和nsecs;缓冲区是写入UUID的地方;缓冲起始位置。一般来说直接使用vvid.v1()即可。v3namespace(命名空间)uuid.v3(name,namespace,buffer,offset)name是uuid的名字;namespace为字符串或16位数组UUID的命名空间;缓冲区的起始位置。一般来说,你可以直接指定名称和命名空间。constMY_NAMESPACE='1b671a64-40d5-491e-99b0-da01ff1f3341';uuid.v3('Hello,World!',MY_NAMESPACE);//?'e8b5a51d-11c8-3310-a6ab-367563f20686'v4random)number(uuid.v4(options,buffer,offset)options包括random和rng;buffer是写入UUID的地方;buffer起始位置。一般来说,直接使用vvid.v4()即可v5namespace(命名空间)uuid.v5(name,namespace,buffer,offset)name为uuid的名称;namespace为字符串或16位数组UUID的命名空间;buffer起始位置。一般来说,可以直接指定名称和命名空间。constMY_NAMESPACE='1b671a64-40d5-491e-99b0-da01ff1f3341';uuid.v5('Hello,World!',MY_NAMESPACE);//?'630eb68f-e0fa-5ecc-887a-7c7a62614681'从上面可以看出,UUID有时间戳、随机数和命名空间三个版本。v1是时间戳;v4是随机数;v3和v5是命名空间。选择合适的UUID版本根据具体业务场景,现有项目uuid应用分析importUUIDfrom"uuid";exportconstuuid=()=>UUID.v4().split("-").join("")/**UUID。v4();//"51a3b08b-41ce-49ca-bda3-717b22bd9b3e"UUID.v4().split("-");//["51a3b08b","41ce","49ca","bda3","717b22bd9b3e"]UUID.v4().split("-").join("");//"51a3b08b41ce49cabda3717b22bd9b3e"**/生成一个长度为32的uuid,去掉-。其实去掉或者不去掉都可以。node-uuid项目实践使用node-uuid替代已有的msgId,增强消息唯一标识的唯一性。我最初的想法是通过node-uuid的v4版本生成一个随机数uuid,唯一标识消息。但是,出于服务器业务实现的考虑,该方案并不可行。原因是服务端需要使用时间戳类型的msgId加上时间戳类型的版本号,最后需要根据时间戳对消息进行排序。因此,暴力替换是不可能的,需要找到另一种不会导致breakchange的解决方案。v1版本的node-uuid或者UUID是时间戳的形式,但是能否引入到项目中还有待商榷。importUUIDfrom"uuid";exportconstuuid=()=>UUID.v1();//"a20c6eb0-d922-11e9-9be9-5ff126df765f"总结与思考虽然timestamp的唯一性很差,可能正好满足一个具体的业务场景,不一定是不好的技术方案自定义随机字符串唯一标识实现其实可以满足唯一性要求。uuid有多个版本,包括时间戳(v1)、随机数(v4)、命名空间(v3、v5),永远没有最好的技术方案。只要最适合业务场景的技术方案,期待与大家交流,共同进步,欢迎大家加入我创建的与前端开发息息相关的技术讨论群:SegmentFault技术圈:ES新规范语法糖SegmentFault专栏:趁年轻做一名优秀的前端工程师知乎专栏:趁年轻做一名优秀的前端工程师:人兽鬼才/excellent_developers努力成为优秀的前端工程师!
