ES6记录异步函数的执行时间详解


Posted in Javascript onAugust 31, 2016

calc

calc 是一个我们想要做剖析(性能分析)的异步函数。按照惯例,它的最后一个参数是一个callback。我们像这样使用 calc

calc(arg, (err, res) => console.log(err || res))

或许,最简单的对 calc 这样的函数来剖析性能的方法是,增加一个计时逻辑到我们需要分析的地方:

const t0 = Date.now()
calc(arg, (err, res) => {
 const t1 = Date.now() 
 console.log(`Log: time: ${t1 = t0}`)
 console.log(err || res)
})

但是,这不是一个可复用的解决方案。每一次我们想要对一个函数计时,我们得引入一个 t0 在外层作用域并且改变 callback 来测量和记录时间。

对我来说理想的方式是能够仅仅通过包装一个异步函数就能够对它进行计时:

timeIt(calc)(arg, (err, res) => console.log(err || res))

timeIt 需要能够很好地对每一个异步函数完成剖析和记录执行时间。

注意到 timeIt(calc) 有与原始的 calc 函数同样的函数签名,即它们接受同样的参数和返回同样的值,它只是增加了一个特性到 cale 上(能够被记录时间的特性)。

calc 和 timeIt(calc) 在任意时刻可以相互替代。

timeIt 本身是一个高阶函数,因为它接受一个函数并返回一个函数。在我们的例子里,它接受 calc 异步函数,并返回一个函数与 calc 有同样的参数和返回值。

下面演示我们如何实现 timeIt 函数:

const timeIt = R.curry((report, f) => (...args) => {

 const t0 = Date.now()
 const nArgs = R.init(args)
 const callback = R.last(args)

 nArgs.push((...args) => {
 const t1 = Date.now()
 callback(...args)
 report(t1 - t0, ...args)
 })

 f(...nArgs)

})

const timeIt1 = timeIt(
 (t, err, res) => console.log(`Log: ${err || res} produced after: ${t}`)
)

const calc = (x, y, z, callback) =>
 setTimeout(() => callback(null, x * y / z), 1000)


calc(18, 7, 3, (err, res) => console.log(err || res))

timeIt1(calc)(18, 7, 3, (err, res) => console.log(err || res))

这个 timeIt 实现接受两个参数:

      report: 一个函数用来生成剖析结果

      f: 我们想要做剖析的异步函数

timeIt1 是一个方便实用的功能函数,它只是用 console.log 记录时间测量结果。我们通过给更通用的 timeIt 函数传入 report 参数来定义它。

我们实现了目标,现在我们可以仅仅将异步函数包装在 timeIt1 中就可以对它计时了:

timeIt1(calc)(18, 7, 3, (err, res) => console.log(err || res))

通用的 timeIt 函数接收一个 report 回调函数和一个异步函数并返回一个新的异步函数,这个异步函数与原函数有同样的参数和返回值。我们可以这么使用:

timeIt(
 (time, ...result) => // report callback: log the time
 , asyncFunc
)(
 parameters…, 
 (...result) => // result of the async function
)

现在让我们深入 timeIt 的实现。我们可以简单地生成一个通用函数类似 timeIt1,因为 timeIt 使用 R.curry 科里化了。

我不打算在这篇文章里讨论科里化,但是下面这段代码演示了科里化的主要用法:

const f = R.curry((x, y) => x + y)
f(1, 10) // == 11
f(1)(10) // == 11

const plus1 = f(1)
plus1(10) // == 11

另一方面,这种方式实现的 timeIt 有几个问题:

(...args) => {
 const t1 = Date.now()
 callback(...args)
 report(t1 — t0, ...args)
}

这是一个匿名函数(又名 lambda,callback),它在原函数异步执行之后被调用。主要的问题是这个函数没有处理异常的机制。如果 callback 抛出异常,report 就永远不会被调用。

我们可以添加一个 try / catch 到这个 lambda 函数里,然而问题的根源是 callback report 是两个 void 函数,它们没有关联在一起。timeIt 包含两个延续(continuations)(report callback)。如果我们只是在 console 下记录执行时间或者如果我们确定不论 report 还是 callback 都不会抛出异常,那么一切正常。但是如果我们想要根据剖析结果来执行一些行为(所谓的自动扩容)那么我们需要强化和厘清我们的程序中的延续序列。

好了,以上这篇文章的全部内容,希望对大家的学习和工作有所帮助,如果有疑问可以留言交流。

Javascript 相关文章推荐
防止动态加载JavaScript引起的内存泄漏问题
Oct 08 Javascript
遍历jquery对象的代码分享
Nov 02 Javascript
JavaScript判断密码强度(自写代码)
Sep 06 Javascript
基于jQuery仿淘宝产品图片放大镜代码分享
Jun 23 Javascript
es6的数字处理的方法(5个)
Mar 16 Javascript
jQuery实现下拉菜单的实例代码
Jun 19 jQuery
JS设计模式之数据访问对象模式的实例讲解
Sep 30 Javascript
JavaScript重复元素处理方法分析【统计个数、计算、去重复等】
Dec 14 Javascript
JS实现图片居中悬浮效果
Dec 25 Javascript
Vue引用Swiper4插件无法重写分页器样式的解决方法
Sep 27 Javascript
微信小程序解析富文本过程详解
Jul 13 Javascript
关于JavaScript轮播图的实现
Nov 20 Javascript
基于angularjs实现图片放大镜效果
Aug 31 #Javascript
用AngularJS的指令实现tabs切换效果
Aug 31 #Javascript
简洁实用的BootStrap jQuery手风琴插件
Aug 31 #Javascript
AngularJS实现一次监听多个值发生的变化
Aug 31 #Javascript
利用Angularjs和bootstrap实现购物车功能
Aug 31 #Javascript
JavaScript String(字符串)对象的简单实例(推荐)
Aug 31 #Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
Aug 31 #Javascript
You might like
php中使用Imagick实现图像直方图的实现代码
2011/08/30 PHP
PHP代码保护--Zend Guard的使用详解
2013/06/03 PHP
PHP 数据结构队列(SplQueue)和优先队列(SplPriorityQueue)简单使用实例
2015/05/12 PHP
PHP设计模式之工厂模式定义与用法详解
2018/04/03 PHP
PHP实现微信公众号验证Token的示例代码
2019/12/16 PHP
找出字符串中出现次数最多的字母和出现次数精简版
2012/11/07 Javascript
JavaScript对象的property属性详解
2014/04/01 Javascript
js判断文本框输入的内容是否为数字
2015/12/23 Javascript
JS iFrame加载慢怎么解决
2016/05/13 Javascript
Vue.js每天必学之过滤器与自定义过滤器
2016/09/07 Javascript
JavaScript实现的CRC32函数示例
2016/11/23 Javascript
详解js的异步编程技术的方法
2017/02/09 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
微信小程序中使用自定义图标(阿里icon)的方法
2018/08/20 Javascript
JS实现的全选、全不选及反选功能【案例】
2019/02/19 Javascript
echarts实现词云自定义形状的示例代码
2019/02/20 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
React组件对子组件children进行加强的方法
2019/06/23 Javascript
ES6学习笔记之let与const用法实例分析
2020/01/22 Javascript
vue 遮罩层阻止默认滚动事件操作
2020/07/28 Javascript
举例讲解Django中数据模型访问外键值的方法
2015/07/21 Python
Python应用03 使用PyQT制作视频播放器实例
2016/12/07 Python
python3爬虫怎样构建请求header
2018/12/23 Python
Python装饰器用法与知识点小结
2020/03/09 Python
跨域修改iframe页面内容详解
2019/10/31 HTML / CSS
临床医学专业个人的自我评价
2013/09/27 职场文书
高级销售员求职信
2013/10/25 职场文书
办公室主任四风问题对照检查材料思想汇报
2014/09/28 职场文书
2015年学校信息技术工作总结
2015/05/25 职场文书
2016年小学“我们的节日·中秋节”活动总结
2016/04/05 职场文书
2019企业给员工的慰问信
2019/06/24 职场文书
导游词之江苏同里古镇
2019/11/18 职场文书
vue前端工程的搭建
2021/03/31 Vue.js
python使用pygame创建精灵Sprite
2021/04/06 Python
Python 阶乘详解
2021/10/05 Python
如何Tomcat中使用ipv6地址
2022/05/06 Servers