今天看cnBeta上说傲游又有更新了,修复了些之前的bug,而自己用的还是2.5.5版,于是便跑到官网准备下个最新的。ps:其实本人浏览器最多用的还是FF啦,无奈国内各大网银又集体鄙视FF,这样IE再破还得当爹样供着,而IE的众多兄弟姐妹叔叔阿姨里面,就Maxthon用的稍多点,在线收藏和内置下载这两样本人还是觉得不错,这个不得不说,FF的内置下载的确弱了点,DownthemAll 感觉也不是太好。
有点偏题了,先说正事。我总觉得这傲游首页有什么东西怪怪的,找了半天发现这下载次数跳的也忒快了点吧,再一看,好家伙都有2亿5千万次了,这个的真实性就不去管了,前段时间FF不是也说下载过10亿了吗。盯着那个数字仔细看了一会儿,跳动的极为有规律,平均下来差不多每秒七、八次,偶尔一秒还会加更多。这我就好奇了,傲游的下载量有这么大吗,还这么有规律?
于是乎翻箱倒柜找齐工具开始研究计数的代码。工具很常见,就FF的两个插件,Web Developer
https://addons.mozilla.org/zh-CN/firefox/addon/60 和Firebug
https://addons.mozilla.org/zh-CN/firefox/addon/1843。
先看计数那块的Html源码
1
<
td
width
="50%"
>
2
<
div
title
="点击进入下载页面"
3
style
="width: 100%; height: 100%; cursor: pointer; overflow: hidden;"
4
onclick
="window.location = 'download.htm'"
>
5
<
a
href
="download.htm"
class
="download-btn"
>
6
<
span
class
="download-title"
>
立即下载 2.5.8
</
span
><
br
/>
7
已有
<
span
id
="counternumber"
>
200,000,000+
</
span
>
次下载
</
a
>
8
</
div
>
9
</
td
>
嗯,table + div 的,次数就是id 为counternumber的那块,刚打开页面时也的确显示的2亿次。继续找脚本文件,页面内的脚本没有什么相关的,外部引用了三个js,script/app.js, script/data.js, script/script.js。中间这个和下载次数无关,先看最后这个文件,里面有这么一段。
1
function
init() {
2
var
initMap
=
{
3
'
index-body
'
:
function
(){
4
initFeatureSlide();
5
buildNewsList(
'
news-list-block
'
, window.newsData,
5
);
6
if
(window.maxWebsite
&&
maxWebsite.updateCounter)
7
maxWebsite.updateCounter();
8
}
9
};
10
var
initKey
=
document.body.id;
11
if
(initKey
&&
initMap[initKey])
12
initMap[initKey]();
13
}
14
window.onload
=
init;
删了些没用的代码,关键在第7行,从名字上来看就是说更新计数器,maxWebsite这个对象是在app.js里面定义的,也就是需要研究的核心。
在app.js的开头定义了几个常量,
1
var
maxWebsite
=
{};
2
3
maxWebsite.counterLoadInterval
=
10000
;
//
ms
4
maxWebsite.counterDataURL
=
"
/api/counter
"
;
5
maxWebsite.failedCounterCall
=
0
;
先放在这儿,继续往下看,找到updateCounter这个函数。
1
maxWebsite.updateCounter
=
function
(){
2
3
if
(maxWebsite.inCounterRequest)
return
;
4
if
(maxWebsite.failedCounterCall
>
10
)
return
;
5
6
//
first time only
7
if
(
!
maxWebsite.targetCounterNumber){
8
maxWebsite.targetCounterNumber
=
0
;
9
maxWebsite.currentCounterNumber
=
0
;
10
maxWebsite.counterDiff
=
0
;
11
12
//
another request
13
maxWebsite.intervalLoad
=
setInterval(
"
maxWebsite.updateCounter()
"
, maxWebsite.counterLoadInterval);
14
15
maxWebsite.intervalTick
=
setInterval(
"
maxWebsite.counterTick()
"
,
1000
);
16
}
17
18
//
load remote data
19
var
req;
20
try
{ req
=
new
XMLHttpRequest(); }
21
catch
(e) {
try
{ req
=
new
ActiveXObject(
"
Microsoft.XMLHTTP
"
); }
22
catch
(e) {
return
null
; }}
23
24
maxWebsite.startCounter
=
new
Date();
25
26
try
{
27
req.open(
"
GET
"
, maxWebsite.counterDataURL
+
'
?
'
+
Math.random(),
true
);
28
req.onreadystatechange
=
get_cb(req);
29
req.send(
''
);
30
maxWebsite.inCounterRequest
=
true
;
31
32
}
catch
(e){
33
maxWebsite.failedCounterCall
++
;
34
}
35
req
=
null
;
36
}
从第7行起,脚本首次执行这个函数时先运行if 里面的代码,三个变量targetCounterNumber,currentCounterNumber,counterDiff 初始化为0,后面会看到核心也就是这三个变量。然后,定义两个自动运行的函数,updateCounter也就是这个函数自己,每隔10秒运行一次(
counterLoadInterval前面定义的常量),
counterTick 每隔1秒运行一次。再往下看,异步读取服务端的数据,中间调用了get_cb(req) 这么一个函数,看它定义。
function
get_cb(req) {
return
function
() {
if
(req.readyState
==
4
){
maxWebsite.updateCounterBinder(req);
req
=
null
;
}
};
}
呃,又是调用,继续看定义。
1
maxWebsite.updateCounterBinder
=
function
(req){
2
3
if
(req.status
==
200
||
req.status
==
0
){
4
var
cnt
=
req.responseText;
5
cnt
=
parseInt(cnt.replace(
/
,
/
g,
''
),
10
);
6
if
(isNaN(cnt))
return
;
7
8
//
first run
9
if
(maxWebsite.targetCounterNumber
==
0
){
10
maxWebsite.targetCounterNumber
=
cnt
-
10
;
11
maxWebsite.currentCounterNumber
=
cnt
-
10
;
12
}
13
14
maxWebsite.inCounterRequest
=
false
;
15
maxWebsite.counterTick(cnt);
16
17
}
else
{
18
maxWebsite.failedCounterCall
++
;
19
}
20
}
从服务端读出来的东西看来是存放在cnt 里面了,而且是一个数字,可以猜测这个数字估计跟首页显示的下载次数有一定关系。首次运行对targetCounterNumber 和 currentCounterNumber进行了初始化。然后调用counterTick 这个函数,前面说这个函数每秒也要调用一次。
1
maxWebsite.counterTick
=
function
(intNumber){
2
3
if
(intNumber){
4
//
calculate diff
5
var
diff
=
intNumber
-
maxWebsite.targetCounterNumber;
6
var
timeDiff
=
maxWebsite.counterLoadInterval
+
(
new
Date()
-
maxWebsite.startCounter);
7
diff
=
diff
/
timeDiff;
8
9
maxWebsite.counterDiff
=
diff
*
1000
;
10
11
maxWebsite.currentCounterNumber
=
maxWebsite.targetCounterNumber;
12
maxWebsite.targetCounterNumber
=
intNumber;
13
}
else
{
14
//
just add up with diff
15
if
(maxWebsite.currentCounterNumber
<
maxWebsite.targetCounterNumber){
16
maxWebsite.currentCounterNumber
+=
maxWebsite.counterDiff;
17
}
18
}
19
maxWebsite.writeCounter(maxWebsite.currentCounterNumber);
20
}
从
updateCounterBinder 这个函数来的调用走if 这部分,而每隔1秒的调用走else这部分。这两块到底是什么,我用firebug 监视了一下,结合具体东西来说。
上面的图是启用Firebug控制台中显示XMLHTTPRequests后截获的请求与响应,这个请求是每10秒发出一次,然后返回一个数赋给cnt,可以看出每10秒,返回值约增长100左右。
现在再看下counterDiff,
currentCounterNumber,targetCounterNumber 这三个数。
在counterTick 中设个断点,从右边可以看出counterDiff的值约为10,currentCounterNumber的值和现在网页上显示的下载数一致,targetCounterNumber比currentCounterNumber稍大。然后targetCounterNumber被intNumber赋值,实际上就是从服务端得到的数cnt。
源码中还有一个函数writeCounter 就是把页面中的数字加上逗号。
从源码中,主要是counterTick函数,可以看出首页显示的下载数就是变量currentCounterNumber的值,每秒增加counterDiff。然后每十秒从服务器取一个数存放到targetCounterNumber中,counterDiff 就是由两次targetCounterNumber的差求的每秒平均。
再通俗点说,傲游首页的下载数每秒按一个固定值增加,然后每十秒从服务器取一个数进行修正,并计算新的增加固定值。
当然,我们不能肯定的说傲游这个下载数有猫腻,毕竟,别人的实际下载数怎么来的从源码中看不出来,而是从
http://www.maxthon.cn/api/counter 取得,这个api如何实现的我就不得而知了。本人不才,到这儿走不下去了,如果有高手还请解说这个api是怎么做的。