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 相关文章推荐
event.srcElement+表格应用
Aug 29 Javascript
屏蔽Flash右键信息的js代码
Jan 17 Javascript
javascript高级学习笔记整理
Aug 14 Javascript
javascript权威指南 学习笔记之变量作用域分享
Sep 28 Javascript
JS 拦截全局ajax请求实例解析
Nov 29 Javascript
javascript 中iframe高度自适应(同域)实例详解
May 16 Javascript
vue实现表格数据的增删改查
Jul 10 Javascript
vue element动态渲染、移除表单并添加验证的实现
Jan 16 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
Jan 27 Javascript
jQuery实现动态加载(按需加载)javascript文件的方法分析
May 31 jQuery
js实现购物车商品数量加减
Sep 21 Javascript
JavaScript中layim之整合右键菜单的示例代码
Feb 06 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
Linux fgetcsv取得的数组元素为空字符串的解决方法
2011/11/25 PHP
初步介绍PHP扩展开发经验分享
2012/09/06 PHP
PHP数据过滤的方法
2013/10/30 PHP
PHP常用处理静态操作类
2015/04/03 PHP
ThinkPHP中session函数详解
2016/09/14 PHP
PHP实现带进度条的Ajax文件上传功能示例
2019/07/02 PHP
PHP中16个高危函数整理
2019/09/19 PHP
aspx中利用js实现确认删除代码
2010/07/22 Javascript
JavaScript.The.Good.Parts阅读笔记(一)假值与===运算符
2010/11/16 Javascript
jquery uaMatch源代码
2011/02/14 Javascript
新鲜出炉的js tips提示效果
2011/04/03 Javascript
如何判断鼠标是否在DIV的区域内
2013/11/13 Javascript
jQuery禁用键盘后退屏蔽F5刷新及禁用右键单击
2016/01/22 Javascript
Bootstrap自定义文件上传下载样式
2016/05/26 Javascript
BootStrap无限级分类(无限极分类封装版)
2016/08/26 Javascript
JS不完全国际化&本地化手册 之 理论篇
2016/09/27 Javascript
js 显示日期时间的实例(时间过一秒加1)
2017/10/25 Javascript
echarts设置图例颜色和地图底色的方法实例
2018/08/01 Javascript
jQuery中常用动画效果函数知识点整理
2018/08/19 jQuery
微信小程序学习笔记之本地数据缓存功能详解
2019/03/29 Javascript
vue实现移动端触屏拖拽功能
2020/08/21 Javascript
分享python数据统计的一些小技巧
2016/07/21 Python
Python 操作MySQL详解及实例
2017/04/30 Python
python中datetime模块中strftime/strptime函数的使用
2018/07/03 Python
如何运行.ipynb文件的图文讲解
2019/06/27 Python
Python基于pillow库实现生成图片水印
2020/09/14 Python
html5的画布canvas——画出简单的矩形、三角形实例代码
2013/06/09 HTML / CSS
总结html5自定义属性有哪些
2020/04/01 HTML / CSS
美国隐形眼镜零售商:LensPure
2019/03/10 全球购物
Osklen官方在线商店:巴西服装品牌
2019/04/25 全球购物
大学班级计划书
2014/04/29 职场文书
学校标语大全
2014/06/19 职场文书
寝室长工作失责检讨书
2014/10/06 职场文书
以权谋私检举信范文
2015/03/02 职场文书
利用Sharding-Jdbc进行分库分表的操作代码
2022/01/22 Java/Android
Spring Cloud OpenFeign模版化客户端
2022/06/25 Java/Android