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 相关文章推荐
可缩放Reloaded-一个针对可缩放元素的复用组件
Mar 10 Javascript
利用jQuery实现可输入搜索文字的下拉框
Oct 23 Javascript
IE 下Enter提交表单存在重复提交问题的解决方法
May 04 Javascript
Javascript判断图片尺寸大小实例分析
Jun 16 Javascript
js获取隐藏元素宽高的实现方法
May 19 Javascript
jQuery post数据至ashx实例详解
Nov 18 Javascript
BootStrap按钮标签及基本样式
Nov 23 Javascript
tab栏切换原理
Mar 22 Javascript
axios基本入门用法教程
Mar 25 Javascript
关于jQuery中fade(),show()起始位置的一点小发现
Apr 25 jQuery
vue 2.x 中axios 封装的get 和post方法
Feb 28 Javascript
JS图片懒加载的优点及实现原理
Jan 10 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图片水印类的封装
2017/07/06 PHP
解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题
2019/10/15 PHP
基于jquery的inputlimiter 实现字数限制功能
2010/05/30 Javascript
用XMLDOM和ADODB.Stream实现base64编码解码实现代码
2010/11/28 Javascript
由Javascript实现的页面日历
2011/11/04 Javascript
JS随机调用指定函数的方法
2015/07/01 Javascript
Vue.js 2.0 和 React、Augular等其他前端框架大比拼
2016/10/08 Javascript
使用jQuery实现两个div中按钮互换位置的实例代码
2017/09/21 jQuery
Angular4学习教程之HTML属性绑定的方法
2018/01/04 Javascript
利用Angular2 + Ionic3开发IOS应用实例教程
2018/01/15 Javascript
使用npm安装最新版本nodejs
2018/01/18 NodeJs
bootstrap fileinput插件实现预览上传照片功能
2018/01/23 Javascript
Es6 Generator函数详细解析
2018/02/24 Javascript
vue-cli+webpack项目 修改项目名称的方法
2018/02/28 Javascript
Vue实现简易翻页效果源码分享
2018/11/08 Javascript
Vue2.0使用嵌套路由实现页面内容切换/公用一级菜单控制页面内容切换(推荐)
2019/05/08 Javascript
inquirer.js一个用户与命令行交互的工具详解
2019/05/18 Javascript
vue实现路由监听和参数监听
2019/10/29 Javascript
three.js中多线程的使用及性能测试详解
2021/01/07 Javascript
理解Python垃圾回收机制
2016/02/12 Python
python 容器总结整理
2017/04/04 Python
Python中elasticsearch插入和更新数据的实现方法
2018/04/01 Python
python try 异常处理(史上最全)
2019/03/07 Python
详解Python匿名函数(lambda函数)
2019/04/19 Python
python全局变量引用与修改过程解析
2020/01/07 Python
Django实现whoosh搜索引擎使用jieba分词
2020/04/08 Python
Django中FilePathField字段的用法
2020/05/21 Python
Keras自动下载的数据集/模型存放位置介绍
2020/06/19 Python
授权委托书样本
2014/04/03 职场文书
经费申请报告
2015/05/15 职场文书
卫生保健工作总结2015
2015/05/18 职场文书
运动会开幕式主持词
2015/07/01 职场文书
2015初中生物教研组工作总结
2015/07/21 职场文书
公证书
2019/04/17 职场文书
我的暑假生活作文(五年级)范文
2019/08/07 职场文书
maven依赖的version声明控制方式
2022/01/18 Java/Android