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 相关文章推荐
基于node.js的快速开发透明代理
Dec 25 Javascript
通过jquery还原含有rowspan、colspan的table的实现方法
Feb 10 Javascript
推荐30个新鲜出炉的精美 jQuery 效果
Mar 26 Javascript
Js数组排序函数sort()介绍
Jun 08 Javascript
javascript学习笔记整理(概述、变量、数据类型简介)
Oct 25 Javascript
JS实现的颜色实时渐变效果完整实例
Mar 25 Javascript
IE下JS保存图片的简单实例
Jul 15 Javascript
jQuery实现的自定义弹出层效果实例详解
Sep 04 Javascript
详解ES6之用let声明变量以及let loop机制
Jul 15 Javascript
vue自定义全局组件(自定义插件)的用法
Jan 30 Javascript
mpvue中配置vuex并持久化到本地Storage图文教程解析
Mar 15 Javascript
React父子组件间的传值的方法
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
Apache设置虚拟WEB
2006/10/09 PHP
详细解读php的命名空间(二)
2018/02/21 PHP
Yii 访问 Gii(脚手架)时出现 403 错误
2018/06/06 PHP
不懂JavaScript应该怎样学
2008/04/16 Javascript
JS时间选择器 兼容IE6,7,8,9
2012/06/26 Javascript
jquery移动listbox的值原理及代码
2013/05/03 Javascript
鼠标经过显示二级菜单js特效
2013/08/13 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
jQuery实现连续动画效果实例分析
2015/10/09 Javascript
JS实现网页上随滚动条滚动的层效果代码
2015/11/04 Javascript
一款简单的jQuery图片标注效果附源码下载
2016/03/22 Javascript
JavaScript编写页面半透明遮罩效果的简单示例
2016/05/09 Javascript
js图片轮播插件的封装
2017/07/21 Javascript
Javascript之图片的延迟加载的实例详解
2017/07/24 Javascript
Vue中computed与methods的区别详解
2018/03/24 Javascript
vue-next/runtime-core 源码阅读指南详解
2019/10/25 Javascript
[40:05]DOTA2上海特级锦标赛A组小组赛#1 EHOME VS MVP.Phx第一局
2016/02/25 DOTA
推荐下python/ironpython:从入门到精通
2007/10/02 Python
使用Python中的cookielib模拟登录网站
2015/04/09 Python
使用Python来开发微信功能
2018/06/13 Python
Python使用itertools模块实现排列组合功能示例
2018/07/02 Python
Opencv+Python实现图像运动模糊和高斯模糊的示例
2019/04/11 Python
Python-Tkinter Text输入内容在界面显示的实例
2019/07/12 Python
Python hmac模块使用实例解析
2019/12/24 Python
html5-canvas中使用clip抠出一个区域的示例代码
2018/05/25 HTML / CSS
瑞典廉价机票预订网站:Seat24
2018/06/19 全球购物
英国网上电器商店:Electricshop
2020/03/15 全球购物
JSP和EJB可以共享HttpSession么?EJB里面可以改变session里面的内容
2013/06/05 面试题
医药类个人求职的自我评价
2014/02/12 职场文书
公司股份合作协议书
2014/12/07 职场文书
小学教学工作总结2015
2015/05/13 职场文书
小学生读书笔记范文
2015/06/30 职场文书
干货!开幕词的写作方法
2019/04/02 职场文书
mysql知识点整理
2021/04/05 MySQL
浅谈Python项目的服务器部署
2021/04/25 Python
Python实现byte转integer
2021/06/03 Python