平时在做开发的时候,有的时候会看到介绍说这个方法没有那个方法效率性能高,那么到底怎么高呢,大多数只是猜猜或者看书上介绍的原理而已。但是我们如何做到定量统计某个函数或者方法的性能呢。
例如往页面中插入大量dom元素的时候,我们一般会用createElement然后再append,然后如果你查资料你会看到建议你使用createDocumentFragment, 因为这个是先见元素插入到内存你中,然后再一次性插入到dom中,避免了频繁重绘。按道理来说确实是这样,那我们怎么亲自见证一下呢。
所以有个方法就是统计函数的执行时间,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function appendDom() { var d = +new Date; for(var i = 0; i < 100000; i++) { var div = document.createElement('div'); div.className = "append"; div.setAttribute('index', i); div.textContent = "dom" + i; //(text); document.body.appendChild(div); } console.log((+new Date) - d + 'ms', 'appendDom'); } appendDom(); |
最后可以得到函数的输出的时间,但是这种方法有个缺点就是侵入性太大了,用起来也不是太方便。总不能每个函数都要这样吧。
所以来正题了,使用aop的思想,aop又叫切面函数 Aspect-oriented programming 从侧面函数侧面出发,不去侵入函数内部,来做一些相应的统计或者非核心逻辑的功能。
参考这篇文章,做了一些修改,封装了before和after函数,来做统计不说那么多废话,show code.
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
//Aop类来扩展JS Function对象 var Aop = function() {}; Aop.prototype = Function.prototype; // 太过于强硬应该有更好的方法 Aop.prototype.before = function(func) { var self = this; return function() { if(func.apply(this, arguments) === false) { return false; } return self.apply(this, arguments); } }; Aop.prototype.after = function(func) { var self = this; return function() { var ret = self.apply(this, arguments); if(ret === false) { return false; } func.apply(this, arguments); return ret; } }; var appendDoms = function() { for(var i = 0; i < 100000; i++) { var div = document.createElement('div'); div.className = "append"; div.setAttribute('index', i); div.textContent = "dom" + i; //(text); document.body.appendChild(div); } }; var docfrag = document.createDocumentFragment(); var appendDomsByFragment = function() { for(var i = 0; i < 100000; i++) { var div = document.createElement('div'); div.className = "append"; div.setAttribute('index', i); div.textContent = "dom" + i; //(text); docfrag.appendChild(div); } document.body.appendChild(docfrag); } // 时间统计函数 var funTimeLog = function(func, func_name) { return func = (function() { return func.before(function() { d = +new Date; }).after(function(){ console.log(+new Date - d + 'ms', func_name); }); })(); } var appendDomsByFragment = funTimeLog(appendDomsByFragment, 'appendDomsByFragment'); var appendDoms = funTimeLog(appendDoms, 'appendDoms'); appendDomsByFragment(); appendDoms(); |
代码比较简单,不做太多的解读。可以看到,这样之后,只要我们需要统计函数执行时间的时候,只需要额外的执行这个函数便是,也不需对原函数进行多余的改变。方便快捷。
只是有一个需要注意的地方就是Aop类来去扩展Function原生类,但是Fuction大家应该都知道,这家伙有点类似与eval函数,是个魔鬼,用的时候要适量和适宜。但是存在就有存在的道理,小心使用就好了。主要是我也没找到很合适的方法。
上面全是代码最后再加个菜。统计静态文件(js)的加载时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function getFileTime(src) { var hj = src.split(".").pop(), begin, resource; switch (hj) { case "js": resource = document.createElement("script"); resource.src = src; document.body.appendChild(resource); begin = +new Date; // 如果想要更精确的值可以使用window.performance.now() break; } resource.addEventListener("load", function() { var end = +new Date; console.log("耗时:", end - begin); }) } getFileTime("http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"); getFileTime("https://code.jquery.com/jquery-2.1.4.min.js"); |
就这么多。demo 运行结果看console
参考:
- https://www.ibm.com/developerworks/cn/web/1212_lincy_jsaop
- http://www.alloyteam.com/2013/08/yong-aop-gai-shan-javascript-dai-ma/
- http://fredrik.appelberg.me/2010/05/07/aop-js/ 强烈建议看一下这篇