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 相关文章推荐
js定义对象或数组直接量时各浏览器对多余逗号的处理(json)
Mar 05 Javascript
JS Map 和 List 的简单实现代码
Jul 08 Javascript
介绍JavaScript的一个微型模版
Jun 24 Javascript
this,this,再次讨论javascript中的this,超全面(经典)
Jan 05 Javascript
angularjs 表单密码验证自定义指令实现代码
Oct 27 Javascript
ie下js不执行的几种可能
Feb 28 Javascript
JavaScript之Canvas_动力节点Java学院整理
Jul 04 Javascript
JS仿QQ好友列表展开、收缩功能(第二篇)
Jul 07 Javascript
浅谈angular.js跨域post解决方案
Aug 30 Javascript
JS+canvas画一个圆锥实例代码
Dec 13 Javascript
javascript中undefined的本质解析
Jul 31 Javascript
Javascript 类型转换、封闭函数及常见内置对象操作示例
Nov 15 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)
2006/10/09 PHP
php5新改动之短标记启用方法
2008/09/11 PHP
php输出指定时间以前时间格式的方法
2015/03/21 PHP
php自动更新版权信息显示的方法
2015/06/19 PHP
让人期待的2011年度最佳 jQuery 插件分享
2012/03/16 Javascript
js字符串转换成xml对象并使用技巧解读
2013/04/18 Javascript
javascript 构造函数方式定义对象
2015/01/02 Javascript
PHP结合jQuery实现红蓝投票功能特效
2015/07/22 Javascript
JS实现常见的TAB、弹出层效果(TAB标签,斑马线,遮罩层等)
2015/10/08 Javascript
javascript实现动态统计图开发实例
2015/11/21 Javascript
整理Javascript基础入门学习笔记
2015/11/29 Javascript
JavaScript的设计模式经典之建造者模式
2016/02/24 Javascript
浅谈js中的引用和复制(传值和传址)
2016/09/18 Javascript
a标签跳转到指定div,jquery添加和移除class属性的实现方法
2016/10/10 Javascript
javascript实现页面滚屏效果
2017/01/17 Javascript
jQuery表格的维护和删除操作
2017/02/03 Javascript
node.js制作一个简单的登录拦截器
2020/02/10 Javascript
c++生成dll使用python调用dll的方法
2014/01/20 Python
python中xrange和range的区别
2014/05/13 Python
简单介绍Python的Tornado框架中的协程异步实现原理
2015/04/23 Python
python编写爬虫小程序
2015/05/14 Python
python根据京东商品url获取产品价格
2015/08/09 Python
Python爬虫DNS解析缓存方法实例分析
2017/06/02 Python
基于django2.2连oracle11g解决版本冲突的问题
2020/07/02 Python
python的dict判断key是否存在的方法
2020/12/09 Python
matplotlib之属性组合包(cycler)的使用
2021/02/24 Python
canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
2018/01/10 HTML / CSS
英国健身专家:WIT Fitness
2021/02/09 全球购物
为什么Runtime.exec(“ls”)没有任何输出?
2014/10/03 面试题
高考备战决心书
2014/03/11 职场文书
跳蚤市场口号
2014/06/13 职场文书
领导干部作风建设剖析材料
2014/10/11 职场文书
教师党的群众路线教育实践活动个人整改措施
2014/11/04 职场文书
幼儿教师2014年度工作总结
2014/12/16 职场文书
个人委托函范文
2015/01/29 职场文书
Windows和Linux上部署Golang并运行程序
2022/04/22 Servers