Fork me on GitHub

After code
  • Geeker
  • Gamer
  • JS
  • C
  • Node
  • React
  • Hippop
  • TDD
That Is An Byte of Me

[afterCode] a bug with Array.sort

29 Apr 2016

又一个你一眼看不出来的Bug

a = [3,2,4]
a.sort(function(x,y){return x>y})
//上面的代码有问题,你信吗;可是下面的测是过的

expect(a).to.deep.equal([2,3,4]) // ok

似乎有了单元测试也不能帮助我们发现问题,在试试这样的测试.

var b= [1,2,10,3,78,8,90,11,3,20,7,4,2]
b.sort(function(x,y){return x>y})

expect(b).to.deep.equal([ 1, 2, 2, 3, 3, 4, 7, 8, 10, 11, 20, 78, 90 ]) // not ok
// b = [ 90,1,11,2,2,3,3,4,7,8,10,20,78]

为什么

代码说明一切 https://github.com/v8/v8/blob/5.2.176/src%2Fjs%2Farray.js#L808 当数组长度小于等于10的时候js的排序是采用的插入排序,插入排序只关心比较函数告诉它x不是比y大,即函数的返回值是不是大于零,如果大于零就交换;而当数组的长度大于10的时候,数组的sort方法就采用快速排序了,而快速排序需要知道xy是大于(1),等于(0),小于(-1)三种关系, 显然如果返回的是布尔值的话,只有1 (Number(true)) 和 零 Number(false), 那么快速排序就不能正确的移动元素的位置了. 那要修复这样错误只要>变成-号就可以了.

真的有这样bug

之前做的应用,使用了mongodb的副本集,因为要机房切换,一次性在新机房创建了很多副本集,本以为这样会让系统中的每个节点的负载更小.但事实情况确实负载变得非常的不均衡,导致业务响应很慢.

查看mongodbnode.js驱动https://github.com/mongodb/node-mongodb-native/blob/V1.4.28/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js#L77,发现在对副本集打分后排序的函数就犯了相同的错误.(现在这问题已经修复了.) 发现这样问题也是恰好我们的副本集的数量超过了10个,触发了这样的问题.

一点点思考

分享到: QQ空间 新浪微博 腾讯微博 微信 更多
comments powered by Disqus