添加不蒜子访问量统计功能及代码阅读。阅读不蒜子源码的想法是想学习一下如何在前端做到访问量统计,看到后面发现好像还是后端完成的。
添加功能
不蒜子访问量统计功能官方网址:http://busuanzi.ibruce.info/
向yilia主题下的/layout/_partial/footer.ejs
文件中添加官网所示的两行代码即可
1 | <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script> |
代码阅读
从官网所示代码中script
标签的src
引用路径可以看出,不蒜子统计功能的源码文件路径为:http://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js
打开后发现代码为压缩后的发布版本,如下:
1 | var bszCaller,bszTag;!function(){var c,d,e,a=!1,b=[];ready=function(c){return a||"interactive"===document.readyState||"complete"===document.readyState?c.call(document):b.push(function(){return c.call(this)}),this},d=function(){for(var a=0,c=b.length;c>a;a++)b[a].apply(document);b=[]},e=function(){a||(a=!0,d.call(window),document.removeEventListener?document.removeEventListener("DOMContentLoaded",e,!1):document.attachEvent&&(document.detachEvent("onreadystatechange",e),window==window.top&&(clearInterval(c),c=null)))},document.addEventListener?document.addEventListener("DOMContentLoaded",e,!1):document.attachEvent&&(document.attachEvent("onreadystatechange",function(){/loaded|complete/.test(document.readyState)&&e()}),window==window.top&&(c=setInterval(function(){try{a||document.documentElement.doScroll("left")}catch(b){return}e()},5)))}(),bszCaller={fetch:function(a,b){var c="BusuanziCallback_"+Math.floor(1099511627776*Math.random());window[c]=this.evalCall(b),a=a.replace("=BusuanziCallback","="+c),scriptTag=document.createElement("SCRIPT"),scriptTag.type="text/javascript",scriptTag.defer=!0,scriptTag.src=a,scriptTag.referrerPolicy="no-referrer-when-downgrade",document.getElementsByTagName("HEAD")[0].appendChild(scriptTag)},evalCall:function(a){return function(b){ready(function(){try{a(b),scriptTag.parentElement.removeChild(scriptTag)}catch(c){bszTag.hides()}})}}},bszCaller.fetch("//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback",function(a){bszTag.texts(a),bszTag.shows()}),bszTag={bszs:["site_pv","page_pv","site_uv"],texts:function(a){this.bszs.map(function(b){var c=document.getElementById("busuanzi_value_"+b);c&&(c.innerHTML=a[b])})},hides:function(){this.bszs.map(function(a){var b=document.getElementById("busuanzi_container_"+a);b&&(b.style.display="none")})},shows:function(){this.bszs.map(function(a){var b=document.getElementById("busuanzi_container_"+a);b&&(b.style.display="inline")})}}; |
使用JavaScript Beautifier
还原,网址为:https://beautifier.io/
还原后的代码如下:
1 | var bszCaller, bszTag; |
短短几十行代码,但是菜鸡的我看了大约一天时间才看出一点逻辑😑,如果说的有什么错误的地方望请指正。
!function(){}()
为立即执行的闭包函数,防止变量名冲突。
var c,d,e,a=!1,b=[];
声明了几个变量,其中a=!1
即a=false
,变量b为数组对象。
接下来就是几个函数了。首先是这个ready函数,一开始这句return给我绕的
1 | return a || "interactive" === document.readyState || "complete" === document.readyState ? c.call(document) : b.push(function() { |
我还寻思这是怎么做到return出来两个对象的,还没[]
,自己新建了个Js文件试了下return a,b
发现最终返回值是b,那么这一个函数执行的逻辑顺序就应该是:判断页面是否加载完成,是则执行c.call(document)
,否则执行b.push(function(){ return c.call(this) })
这一句,最终返回对象this
。
此处的或语句个人猜想是只要三个条件满足其一(a==true / "interactive" === document.readyState / 三元表达式
)则返回this
对象,此处的this
对象应该是浏览器窗口对象。
d这个函数中调用了apply方法,而apply方法一般是用于处理数组的,结果就陷入了误区(感谢@situ2001的提醒)。
这里调用了apply方法传入的document应该是此处的第一个参数arguementForThis而非后面的数组,目测是用来将document传给当前的this。
e这个函数中使用了容易被忽略的逗号运算符,从左往右依次计算表达式的值,最终结果为最右表达式的值。
接下来的document.addEventListener
目测是添加事件监听器并进行异步请求。
window==window.top&&
这句通过百度了解到应该是调用了IE特有的doScroll方法以判断页面DOM是否加载完毕。
bszCaller
内创建了两个函数。
fetch函数第一行var c="BusuanziCallback_"+Math.floor(1099511627776*Math.random());
创建一个随机数并与BusuanziCallback_
拼接。看到这里我才发现这个访问量统计实际上还是在后端做的,此处创建随机的Callback变量名应该就是为了在数据库中分别存储每个网站对应的访问量。
a=a.replace("=BusuanziCallback","="+c),
将传入的变量a重新赋值。
document.getElementsByTagName("HEAD")[0].appendChild(scriptTag)
在html页面的head部分插入script标签。个人猜测此处插入的script标签中的Js文件才是真正的访问量统计相关的Javascript代码段。
evalCall函数中调用了Javascript原生的ready函数,在函数执行完毕即访问量统计已经显示到页面上之后尝试将创建的script标签删除,删除失败则调用bszTag类中的hides方法。此处隐藏的应该就是上面所插入的那个Js文件的真实地址。
之后bszCaller.fetch()
这句调用了bszCaller的fetch方法并传入参数a="//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback",b=function(a){}
。这里实际上就是在向后端服务器请求数据了。
bszTag
对象内创建了三个函数,其中texts
和shows
在bszCaller.fetch()
中使用,应该与访问量显示相关。hides
在bszCaller.evalCall()
中使用,应该是用于隐藏真实的Javascript文件地址。
所以实际上执行的顺序应该是:
1 | var bszCaller,bszTag; |
同时,个人猜测,不蒜子访问量统计文件中生成的随机数与域名有关(因为localhost:4000的访问量巨大😏)。
知识浅薄,如有错漏,烦请指正😊。
发布时间: 2021-02-18
最后更新: 2021-05-01
本文标题: 添加不蒜子访问量统计功能
本文链接: https://cloudflare.luhawxem.com/2021/02/18/BusuanziCounter/
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可。转载请注明出处!