在JS中统计函数执行次数与执行时间
假如想统计JS中的函数执行次数最多的是哪个,执行时间最长的是哪个,该怎么做呢?
一、统计函数执行次数
常规的方法可以使用 console.log 输出来肉眼计算有多少个输出
不过在Chrome中内置了一个 console.count 方法,可以统计一个字符串输出的次数。我们可以利用这个来间接地统计函数的执行次数
function someFunction() {
console.count('some 已经执行');
} function otherFunction() {
console.count('other 已经执行');
} someFunction(); // some 已经执行: 1
someFunction(); // some 已经执行: 2
otherFunction(); // other 已经执行: 1 console.count(); // default: 1
console.count(); // default: 2
不带参数则为 default 值,否则将会输出该字符串的执行次数,观测起来还是挺方便的
当然,除了输出次数之外,还想获取一个纯粹的次数值,可以用装饰器将函数包装一下,内部使用对象存储调用次数即可
var getFunCallTimes = (function() { // 装饰器,在当前函数执行前先执行另一个函数
function decoratorBefore(fn, beforeFn) {
return function() {
var ret = beforeFn.apply(this, arguments); // 在前一个函数中判断,不需要执行当前函数
if (ret !== false) {
fn.apply(this, arguments);
}
};
} // 执行次数
var funTimes = {}; // 给fun添加装饰器,fun执行前将进行计数累加
return function(fun, funName) {
// 存储的key值
funName = funName || fun; // 不重复绑定,有则返回
if (funTimes[funName]) {
return funTimes[funName];
} // 绑定
funTimes[funName] = decoratorBefore(fun, function() {
// 计数累加
funTimes[funName].callTimes++; console.log('count', funTimes[funName].callTimes);
}); // 定义函数的值为计数值(初始化)
funTimes[funName].callTimes = 0; return funTimes[funName];
}
})();
function someFunction() { } function otherFunction() { } someFunction = getFunCallTimes(someFunction, 'someFunction'); someFunction(); // count 1
someFunction(); // count 2
someFunction(); // count 3
someFunction(); // count 4 console.log(someFunction.callTimes); // otherFunction = getFunCallTimes(otherFunction);
otherFunction(); // count 1
console.log(otherFunction.callTimes); // otherFunction(); // count 2
console.log(otherFunction.callTimes); //
二、统计函数执行时间
Chrome中内置了 console.time 和 console.timeEnd 来打点计算时间
console.time(); for (var i = 0; i < 100000; ++i) { } console.timeEnd(); // default: 1.77197265625ms
不传入参数的话,将以default输出毫秒值
我们可以封装一下,传入函数名称,类似上面的做法,使用装饰器在函数执行前后进行处理
var getFunExecTime = (function() { // 装饰器,在当前函数执行前先执行另一个函数
function decoratorBefore(fn, beforeFn) {
return function() {
var ret = beforeFn.apply(this, arguments); // 在前一个函数中判断,不需要执行当前函数
if (ret !== false) {
fn.apply(this, arguments);
}
};
} // 装饰器,在当前函数执行后执行另一个函数
function decoratorAfter(fn, afterFn) {
return function() {
fn.apply(this, arguments);
afterFn.apply(this, arguments);
};
} // 执行次数
var funTimes = {}; // 给fun添加装饰器,fun执行前后计时
return function(fun, funName) {
return decoratorAfter(decoratorBefore(fun, function() {
// 执行前
console.time(funName);
}), function() {
// 执行后
console.timeEnd(funName);
});
}
})();
那么调用的时候,就不需要理会如何计时了
function someFunction() {
for (var i = 0; i < 100000; ++i) { }
} function otherFunction() {
for (var i = 0; i < 10000000; ++i) { }
} someFunction = getFunExecTime(someFunction, 'someFunction');
someFunction(); // someFunction: 1.616943359375ms otherFunction = getFunExecTime(otherFunction, 'otherFunction');
otherFunction(); // otherFunction: 18.157958984375ms
Chrome的Console API毕竟不是标准的,除了使用它之外,还可以选择日期插件 Date 中的 getTime now 相关方法
然而使用Date对象来计算耗时并不正统,推荐使用标准的 performance.now
var start = performance.now(); console.time(); for (var i = 0; i < 10000000; ++i) { } var end = performance.now(); console.timeEnd(); // default: 23.598876953125ms console.log(end - start); // 23.600000015459955
可以看到,它们是相差不大的
使用类似的方法,将它包装起来以便方便调用
var getFunExecTime = (function() { // 装饰器,在当前函数执行前先执行另一个函数
function decoratorBefore(fn, beforeFn) {
return function() {
var ret = beforeFn.apply(this, arguments); // 在前一个函数中判断,不需要执行当前函数
if (ret !== false) {
fn.apply(this, arguments);
}
};
} // 装饰器,在当前函数执行后执行另一个函数
function decoratorAfter(fn, afterFn) {
return function() {
fn.apply(this, arguments);
afterFn.apply(this, arguments);
};
} // 执行次数
var funTimes = {}; // 给fun添加装饰器,fun执行前后计时
return function(fun, funName) {
funName = funName || fun; if (funTimes[funName]) {
return funTimes[funName];
} // 绑定
funTimes[funName] = decoratorAfter(decoratorBefore(fun, function() {
// 执行前
funTimes[funName].timestampStart = performance.now();
}), function() {
// 执行后
funTimes[funName].timestampEnd = performance.now(); // 将执行耗时存入
funTimes[funName].valueOf = function() {
return this.timestampEnd - this.timestampStart;
};
}); return funTimes[funName];
}
})();
function someFunction() {
for (var i = 0; i < 100000; ++i) { }
} function otherFunction() {
for (var i = 0; i < 10000000; ++i) { }
} // 包装
someFunction = getFunExecTime(someFunction);
// 执行
someFunction();
// 获取耗时,可直接使用函数的 valueOf
console.log(+someFunction); // 2.0999999847263098 otherFunction = getFunExecTime(otherFunction, 'otherFunction');
otherFunction();
console.log(+otherFunction); // 21.00000000745058
三、如何控制函数的调用次数
也可以通过闭包来控制函数的执行次数
function someFunction() {
console.log(1);
} function otherFunction() {
console.log(2);
} function setFunCallMaxTimes(fun, times, nextFun) {
return function() {
if (times-- > 0) {
// 执行函数
return fun.apply(this, arguments);
} else if (nextFun && typeof nextFun === 'function') {
// 执行下一个函数
return nextFun.apply(this, arguments);
}
};
} var fun = setFunCallMaxTimes(someFunction, 3, otherFunction); fun(); //
fun(); //
fun(); //
fun(); //
fun(); //
四、如何控制函数的执行时间
因为JS是单线程的,控制函数的执行时间相对来说挺麻烦
通过 async await yield 等异步特性,也许还是能办到的
在React 16中的 Fiber 机制,在某种意义上是能控制函数的执行时机,得空再去看看它是怎么实现的吧
在JS中统计函数执行次数与执行时间的更多相关文章
- 在JS中统计函数执行次数
一.统计函数执行次数 常规的方法可以使用 console.log 输出来肉眼计算有多少个输出 不过在Chrome中内置了一个 console.count 方法,可以统计一个字符串输出的次数.我们可以利 ...
- 进阶学习js中的执行上下文
在js中的执行上下文,菜鸟入门基础 这篇文章中我们简单的讲解了js中的上下文,今天我们就更进一步的讲解js中的执行上下文. 1.当遇到变量名和函数名相同的问题. var a = 10; functio ...
- js中的执行环境及作用域
最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执 ...
- js中的执行上下文,菜鸟入门基础。
console.log(a); //Uncaught ReferenceError: a is not defined 因为没有定义a所以报错了. var a = 52; console.log(a) ...
- Promise对象及它在js中的执行顺序
关于Promise对象的学习及它的执行顺序 学习阮一峰老师的ES6入门后的记录 1.promise的定义 promise是一个对象,通常包裹着一个异步操作,promise对象提供一些接口的方法,返回一 ...
- JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)
1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...
- JS中函数执行顺序的问题?
作者:知乎用户链接:https://www.zhihu.com/question/23564807/answer/82996422来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- js中的执行环境和作用域链
首先介绍一些即将用到的概念: 执行环境: 它定义了变量和函数有权访问其他数据的范围,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中. 所有javasc ...
- 关于js中立即执行的匿名函数写法
/*最流行的写法*/ (function() { alert("run!") })(); /* !号可以有1~正无穷个,所以这一种就可以衍生无数种方式 */ !!!(functio ...
随机推荐
- uni-app开发一次,覆盖多端的前端框架
uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架,开发者编写一套代码,可编译到iOS.Android.H5.小程序等多个平台. 一套代码,运行多个平台 uni-app实现了一套代码, ...
- Java集合:LinkedList源码解析
Java集合---LinkedList源码解析 一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据re ...
- 小米open-falcon监控系统接入手册
一.新项目接入 0.官方文档: https://book.open-falcon.org/zh_0_2/usage/getting-started.html 1.联系运维人员确定可以使用监控系统: ( ...
- CSS Grid
效果图如上所示 <!DOCTYPE html> <html> <head> <title>练习</title> </head> ...
- VIP之CSC
Color Space Converter II(CSC) 不同的色彩空间用于不同的设备.如RGB一般用于电脑显示器,YCbCr一般用于数字电视,IP还支持最小和最大的保护带[个人理解,这里的保护 ...
- opencv源码编写规则
OPENCV作为一种开源的计算机视觉库,我们有必要去了解这个库的一些编码格式及文件结构. 1.文档命名规则 必须将所有功能放入一个或多个.cpp和.hpp文件到OpenCV的相应模块中,或者如果贡献的 ...
- web安全基础
web安全备忘 主机系统安全防护:防火墙控制 Web是一个分布式系统,一个站点多个主机布置,一主机布置多个站点:并发,异步,同步 主机安全配置文件修改与强化 web站点数据验证逻辑的常用技巧:功能性代 ...
- A - 饭卡
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够).所以大家 ...
- CPU Hardwar
GPU负责把线程块分配到各个SM上处理. CUDA对申请的线程块何时运行,以及在哪个SM上运行是没有保证的.这恰好是GPU的优势,这种方式带来了灵活性,不需程序根据SM的数量去配置程序. 但是一个bl ...
- 「WC2018」州区划分(FWT)
「WC2018」州区划分(FWT) 我去弄了一个升级版的博客主题,比以前好看多了.感谢 @Wider 不过我有阅读模式的话不知为何 \(\text{LATEX}\) 不能用,所以我就把这个功能删掉了. ...