正文
var m = [1,2,3,...]; //为一个很长很长的数组。
var o = Math.floor(m.length/8);
var p = m.length % 8 ;
var i = 0;
do{
switch(p){
case 0 : console.log(m[i++]);
case 7 : console.log(m[i++]);
case 6 : console.log(m[i++]);
case 5 : console.log(m[i++]);
case 4 : console.log(m[i++]);
case 3 : console.log(m[i++]);
case 2 : console.log(m[i++]);
case 1 : console.log(m[i++]);
}
p = 0;
}while(--o);
书上的达夫设备的代码如上,但是在我看来这段代码是有问题的,除非m也就是初始循环次数是8的整倍数,否则循环会少执行一轮,也就是8次。不过没有找到这本书的勘误,自行完善了一下这里的代码:
var m = [1,2,3,...];
var o = Math.floor(m.length/8);
var p = m.length % 8 ;
p === 0 ? '' : o++;
var i = 0;
do{
switch(p){
case 0 : console.log(m[i++]);
case 7 : console.log(m[i++]);
case 6 : console.log(m[i++]);
case 5 : console.log(m[i++]);
case 4 : console.log(m[i++]);
case 3 : console.log(m[i++]);
case 2 : console.log(m[i++]);
case 1 : console.log(m[i++]);
}
p = 0;
}while(--o);
理解上面的代码需要首先明确一点,不管是在C中还是JavaScript中,如果switch语句中没有break,则会在匹配到第一个case并执行后执行下一个case中的操作,不管下一个case是否匹配,直到遇到break或者结束的大括号,当然,return也可以。
上面switch版本的达夫设备的改进版是去掉了switch而变得更快,书中的代码是个死循环(难道因为我看的是pdf版本的有误,原书是对的吗),就不贴出来祸害人了,我这梳理后重写的代码如下:
var m = [1,2,3,...];
var p = m.length % 8 ;
while(p){
console.log(m[--p]);
}
var i = m.length;
var o = Math.floor(m.length/8);
while(o--){
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
console.log(m[--i]);
}
这个版本中的达夫设备将主循环和余数处理的部分分开,并将原数组进行倒序处理。代码很易懂就不多说。
在实测中,达夫设备的性能并不比传统的for循环快多少,甚至普遍会慢那么一点点(FireFox不管处理什么样的循环,都比Chrome慢三倍,这个必须吐槽一下),这是因为在现代浏览器中,随着设备性能的提升,浏览器的实现对循环的算法优化的越来越好,在浏览器内部处理循环时也会采用自己独特的算法提升循环的性能,编程时达夫设备带来的性能提升已经慢慢的变得不足为道;加上达夫设备这种写法,对于代码可读性很不友好,因此现在已经慢慢越来越少会有人采用这样的方式来做性能优化。但是达夫设备最初这种诡异的写法和思路,还是惊艳了很多人的,值得我们思考。