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比较文档位置
Apr 08 Javascript
js 遍历对象的属性的代码
Dec 29 Javascript
仿谷歌主页js动画效果实现代码
Jul 14 Javascript
jQuery禁用键盘后退屏蔽F5刷新及禁用右键单击
Jan 22 Javascript
Zabbix添加Node.js监控的方法
Oct 20 Javascript
AngularJS路由切换实现方法分析
Mar 17 Javascript
vue.js中Vue-router 2.0基础实践教程
May 08 Javascript
node.js通过axios实现网络请求的方法
Mar 05 Javascript
react 创建单例组件的方法
Apr 26 Javascript
JS中判断字符串存在和非空的方法
Sep 12 Javascript
jQuery中each和js中forEach的区别分析
Feb 27 jQuery
详解Vite的新体验
Feb 22 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(3) php 函数
2010/02/15 PHP
PHP简单选择排序算法实例
2015/01/26 PHP
PHP 中 Orientation 属性判断上传图片是否需要旋转
2015/10/16 PHP
在线编辑器的实现原理(兼容IE和FireFox)
2007/03/09 Javascript
在你的网页中嵌入外部网页的方法
2007/04/02 Javascript
javascript dom代码应用 简单的相册[firefox only]
2010/06/12 Javascript
超炫的jquery仿flash导航栏特效
2014/11/11 Javascript
jquery可定制的在线UEditor编辑器
2015/11/17 Javascript
基于javascript的Form表单验证
2016/12/29 Javascript
基于JavaScript实现自定义滚动条
2017/01/25 Javascript
10个最优秀的Node.js MVC框架
2017/08/24 Javascript
基于require.js的使用(实例讲解)
2017/09/07 Javascript
vue实现登陆登出的实现示例
2017/09/15 Javascript
JS正则表达式封装与使用操作示例
2019/05/15 Javascript
vue键盘事件点击事件加native操作
2020/07/27 Javascript
javascript实现打砖块小游戏(附完整源码)
2020/09/18 Javascript
在Python中使用SimpleParse模块进行解析的教程
2015/04/11 Python
python opencv人脸检测提取及保存方法
2018/08/03 Python
python 用户交互输入input的4种用法详解
2019/09/24 Python
PyTorch中的拷贝与就地操作详解
2020/12/09 Python
python pygame 愤怒的小鸟游戏示例代码
2021/02/25 Python
HTML5 video 视频标签使用介绍
2014/02/03 HTML / CSS
找到您丢失的钥匙、钱包和手机:Tile
2017/05/19 全球购物
程序员经常用到的UNIX命令
2015/04/13 面试题
房地产开发计划书
2014/01/10 职场文书
师范教师毕业鉴定
2014/01/13 职场文书
关于青春的演讲稿
2014/05/05 职场文书
法制宣传教育方案
2014/05/09 职场文书
新学期开学演讲稿
2014/05/24 职场文书
日语专业毕业生自荐书
2014/06/18 职场文书
2014个人反腐倡廉思想汇报
2014/09/15 职场文书
前台文员岗位职责
2015/02/04 职场文书
经营目标责任书
2015/05/08 职场文书
2016中秋节问候语
2015/11/11 职场文书
科学家研发出新型速效酶,可在 24 小时内降解塑料制品
2022/04/29 数码科技
python turtle绘图
2022/05/04 Python