七牛 guid 解析

很久之前接过七牛的接口,在七牛的 SDK 中找到一个很有意思的 guid
算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// https://github.com/qiniu/js-sdk/blob/d1792bd4cdaa02ea677aef22539a5f1c1e8a942f/test/demo1/js/moxie.js#L525
/**
Generates an unique ID. The only way a user would be able to get the same ID is if the two persons
at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
to be hit with an asteroid.
@method guid
@static
@param {String} prefix to prepend (by default 'o' will be prepended).
@method guid
@return {String} Virtually unique id.
*/
var guid = (function() {
var counter = 0;

return function(prefix) {
var guid = new Date().getTime().toString(32), i;

for (i = 0; i < 5; i++) {
guid += Math.floor(Math.random() * 65535).toString(32);
}

return (prefix || 'o_') + guid + (counter++).toString(32);
};
}());

一个挺有趣的 guid 生成器,注释上说:撞码的概率好比小行星撞地球

这个代码中还是存在问题:

  1. counter会过长
  2. prefix无法置空

代码优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const guid = (function() {
let counter = 0;

return function(prefix) {
counter = counter % (32 * 3);
let guid = new Date().getTime().toString(32);

for (let i = 0; i < 5; i++) {
guid += Math.floor(Math.random() * 65535).toString(32);
}

return (!prefix ? prefix : "o_") + guid + (counter++).toString(32);
};
}());

做了一些改变

  1. 允许置空prefix
  2. counter大小被限制

但是,这种 guid 作为主的方式其实对 mysql 并不友好,一旦数据量上来,查询速度就会慢下来,所以还是建议使用数字来做主键。然而我们并不希望把自增 id 暴露到外部,这时候可能就需要使用雪花算法了。不过这里就不对雪花算法进行描述了,哪天徒手写一个再写博客。