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 相关文章推荐
jquery提示 "object expected"的解决方法
Dec 13 Javascript
自用js开发框架小成 学习js的朋友可以看看
Nov 16 Javascript
jQuery旋转插件—rotate支持(ie/Firefox/SafariOpera/Chrome)
Jan 16 Javascript
document节点对象的获取方式示例介绍
Dec 24 Javascript
jquery实现点击消失的代码
Mar 03 Javascript
jQuery淡入淡出元素让其效果更为生动
Sep 01 Javascript
JavaScript中document对象使用详解
Jan 06 Javascript
使用基于Node.js的构建工具Grunt来发布ASP.NET MVC项目
Feb 15 Javascript
JavaScript sort数组排序方法和自我实现排序方法小结
Jun 06 Javascript
AngularJS实现表单验证功能详解
Oct 12 Javascript
详解Vue-cli中的静态资源管理(src/assets和static/的区别)
Jun 19 Javascript
vue项目中锚点定位替代方式
Nov 13 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文章采集URL补全函数(FormatUrl)
2012/08/02 PHP
编写Smarty插件在模板中直接加载数据的详细介绍
2013/06/26 PHP
php去除字符串换行符示例分享
2014/02/13 PHP
php实现微信发红包
2015/12/05 PHP
php.ini中date.timezone设置详解
2016/11/20 PHP
php创建多级目录与级联删除文件的方法示例
2019/09/12 PHP
jQuery Jcrop插件实现图片选取功能
2011/11/23 Javascript
js获取下拉列表框中的value和text的值示例代码
2014/01/11 Javascript
js检测输入内容全为空格的方法
2014/05/03 Javascript
使用AngularJS来实现HTML页面嵌套的方法
2015/06/17 Javascript
学习使用grunt来打包JavaScript和CSS程序的教程
2016/01/04 Javascript
jQuery实现根据滚动条位置加载相应内容功能
2016/07/18 Javascript
详解Angualr 组件间通信
2017/01/21 Javascript
jQuery EasyUI Layout实现tabs标签的实例
2017/09/26 jQuery
为什么说JavaScript预解释是一种毫无节操的机制详析
2018/11/18 Javascript
Node.js 多进程处理CPU密集任务的实现
2019/05/26 Javascript
移动端手指操控左右滑动的菜单
2019/09/08 Javascript
用JavaScript实现贪吃蛇游戏
2020/10/23 Javascript
关于Python面向对象编程的知识点总结
2017/02/14 Python
python常见排序算法基础教程
2017/04/13 Python
用Pygal绘制直方图代码示例
2017/12/07 Python
详解如何利用Cython为Python代码加速
2018/01/27 Python
python3+PyQt5+Qt Designer实现堆叠窗口部件
2018/04/20 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
18个Python脚本可加速你的编码速度(提示和技巧)
2019/10/17 Python
如何获取Python简单for循环索引
2019/11/21 Python
Pytorch 使用CNN图像分类的实现
2020/06/16 Python
香港士多网上超级市场:Ztore
2021/01/09 全球购物
命名空间(namespace)和程序集(Assembly)有什么区别
2015/09/25 面试题
求职个人评价范文
2014/04/09 职场文书
《一个小村庄的故事》教学反思
2014/04/13 职场文书
初三学生评语大全
2014/04/24 职场文书
治庸问责心得体会
2014/09/12 职场文书
2019年亲子运动会口号
2019/10/11 职场文书
导游词之永泰公主墓
2019/12/04 职场文书
python 中的@运算符使用
2021/05/26 Python