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对select动态添加和删除OPTION示例代码
Aug 12 Javascript
可自己添加html的伪弹出框实现代码
Sep 08 Javascript
window.navigate 与 window.location.href 的使用区别介绍
Sep 21 Javascript
由ReactJS的Hello world说开来
Jul 02 Javascript
JS实现DIV容器赋值的方法
Dec 14 Javascript
JS判断日期格式是否合法的简单实例
Jul 11 Javascript
深入理解 JavaScript 中的 JSON
Apr 06 Javascript
chorme 浏览器记住密码后input黄色背景处理方法(两种)
Nov 22 Javascript
细说webpack源码之compile流程-入口函数run
Dec 26 Javascript
JS中数据结构与算法---排序算法(Sort Algorithm)实例详解
Jun 17 Javascript
使用 Angular RouteReuseStrategy 缓存(路由)组件的实例代码
Nov 01 Javascript
js get和post请求实现代码解析
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
php daodb插入、更新与删除数据
2009/03/19 PHP
Ping服务的php实现方法,让网站快速被收录
2012/02/04 PHP
PHP中“简单工厂模式”实例代码讲解
2012/09/04 PHP
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
PHP数组的定义、初始化和数组元素的显示实现代码
2016/11/05 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
在php的yii2框架中整合hbase库的方法
2018/09/20 PHP
一个js实现的所谓的滑动门
2007/05/23 Javascript
纯js简单日历实现代码
2013/10/05 Javascript
javascript数组输出的两种方式
2015/01/13 Javascript
深入分析jQuery的ready函数是如何工作的(工作原理)
2015/12/17 Javascript
js事件处理程序跨浏览器解决方案
2016/03/27 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
Vue页面骨架屏的实现方法
2018/05/22 Javascript
vue调试工具vue-devtools安装及使用方法
2018/11/07 Javascript
Vuex mutitons和actions初使用详解
2019/03/04 Javascript
layui输入框中只允许输入整数的实现方法
2019/09/18 Javascript
微信用户访问小程序的登录过程详解
2019/09/20 Javascript
js瀑布流布局的实现
2020/06/28 Javascript
Python pymongo模块用法示例
2018/03/31 Python
Python异常处理操作实例详解
2018/05/10 Python
python使用正则表达式来获取文件名的前缀方法
2018/10/21 Python
python hook监听事件详解
2018/10/25 Python
python如何实现视频转代码视频
2019/06/17 Python
PyQt5笔记之弹出窗口大全
2019/06/20 Python
Python实现中值滤波去噪方式
2019/12/18 Python
tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this T
2020/06/22 Python
造价工程师个人求职信
2013/09/21 职场文书
超市营业员岗位职责
2013/12/20 职场文书
个人简历自荐信
2014/06/26 职场文书
文秘应届生求职信
2014/07/05 职场文书
使用redis实现延迟通知功能(Redis过期键通知)
2021/09/04 Redis
Vue2.0搭建脚手架
2022/03/13 Vue.js
“鬼灭之刃”热度不减,其成功背后的原因是什么?
2022/03/22 日漫
Java 数据结构七大排序使用分析
2022/04/02 Java/Android
MySQL 语句执行顺序举例解析
2022/06/05 MySQL