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 两个窗体之间传值实现代码
Sep 25 Javascript
jquery UI 1.72 之datepicker
Dec 29 Javascript
jquery实现checkbox 全选/全不选的通用写法
Feb 22 Javascript
JS获取select的value和text值的简单实例
Feb 26 Javascript
jQuery对象的length属性用法实例
Dec 27 Javascript
JavaScript在浏览器标题栏上显示当前日期和时间的方法
Mar 19 Javascript
JS onkeypress兼容性写法详解
Apr 27 Javascript
jQuery多个版本和其他js库冲突的解决方法
Aug 11 Javascript
Vue实现动态响应数据变化
Apr 28 Javascript
利用prop-types第三方库对组件的props中的变量进行类型检测
May 02 Javascript
vue.js项目nginx部署教程
Apr 05 Javascript
Element-ui之ElScrollBar组件滚动条的使用方法
Sep 14 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图像处理类库及演示分享
2015/05/17 PHP
PHP连接数据库实现注册页面的增删改查操作
2016/03/27 PHP
tp5(thinkPHP5)框架实现多数据库查询的方法
2019/01/10 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
再谈IE中Flash控件的自动激活 ObjectWrap
2007/03/09 Javascript
Cookie 注入是怎样产生的
2009/04/08 Javascript
使弱类型的语言JavaScript变强势
2009/06/22 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
一个JavaScript去除字符串末尾的空白实例代码
2014/09/22 Javascript
禁止按回车键提交表单的方法
2015/06/11 Javascript
jQuery实现的图片轮播效果完整示例
2016/09/12 Javascript
JavaScript 闭包详细介绍
2016/09/28 Javascript
AngularJS递归指令实现Tree View效果示例
2016/11/07 Javascript
easyui导出excel无法弹出下载框的快速解决方法
2016/11/10 Javascript
node.js中实现kindEditor图片上传功能的方法教程
2017/04/26 Javascript
javascript 开发之百度地图使用到的js函数整理
2017/05/19 Javascript
基于es6三点运算符的使用方法(实例讲解)
2017/10/12 Javascript
Vue.js 2.0和Cordova开发webApp环境搭建方法
2018/02/26 Javascript
vue 实现强制类型转换 数字类型转为字符串
2019/11/07 Javascript
解决Vue打包上线之后部分CSS不生效的问题
2019/11/12 Javascript
linux 下以二进制的方式安装 nodejs
2020/02/12 NodeJs
[01:09:40]Newbee vs Pain 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python中类型检查的详细介绍
2017/02/13 Python
python用fsolve、leastsq对非线性方程组求解
2018/12/15 Python
Python列表的切片实例讲解
2019/08/20 Python
Python使用selenium + headless chrome获取网页内容的方法示例
2019/10/16 Python
python 视频逐帧保存为图片的完整实例
2019/12/10 Python
美国礼品卡商城: Gift Card Mall
2017/08/25 全球购物
一套Delphi的笔试题一
2016/02/14 面试题
生物科学专业个人求职信范文
2013/12/05 职场文书
服务员态度差检讨书
2014/10/28 职场文书
党员违纪检讨书怎么写
2014/11/01 职场文书
2015年教师教学工作总结
2015/04/28 职场文书
解析原生JS getComputedStyle
2021/05/25 Javascript
Python必备技巧之字符数据操作详解
2022/03/23 Python
Elasticsearch 批量操作
2022/04/19 Python