Node.js 实现简单的无侵入式缓存框架的方法


Posted in Javascript onJuly 21, 2019

前言

python 的flask.ext.cache 通过注解这样对方法返回结果进行缓存:

@cache.cached(timeout=300, key_prefix='view_%s', unless=None)
def hello(name=None):
  print 'view hello called'
  return render_template('hello.html', name=name)

这类实现方式对业务逻辑没有丝毫的侵入性,非常之优雅。

最近在做 Node.js 地项目,然而 js ES 7 之前都不支持注解,目前见到的缓存框架虽然在 API 设计上都很简洁、很有想法。

可是痛点在于它们都是侵入式的,需要在业务逻辑代码中插入缓存逻辑,这些方式很不优雅。

正题

今天花点时间研究下js有没有办法,以比较优雅地方法实现缓存。

我对缓存框架的诉求:

  • 不对原方法进行更改
  • 能实现对不同参数地缓存
  • 支持缓存时间

我了解到的 js 能力:

  1. 隐藏参数arguments可以获取参数列表
  2. prototype 可用来重写覆盖原方法

可行性?

看了看 prototype 文档

直觉告诉我看起来可行,以下是官方的说明:

当一个函数被调用时,调用的参数被保留在类似数组 "变量" 的参数中。例如, 在调用 "myFn (a、b、c)"时, 在myFn 的主体内的参数将包含 3个类似数组的元素对应于 (a、b、c)。 使用钩子修改原型时,只需通过调用该函数的 apply (),将 this 与参数 (调用状态) 传递给当前行为。这种模式可以用于任何原型,如 Node.prototype、 Function.prototype 等.

var current = Object.prototype.valueOf;
// 由于我的属性 "-prop-value"是交叉性的, 并不总是
// 在同一个原型链上,我想要修改 Object.prototype: 
Object.prototype.valueOf = function() {
 if (this.hasOwnProperty('-prop-value')) {
  return this['-prop-value'];
 } else {
  // 它看起来不像我的对象之一,因此,让我们退回到 
  // 默认行为,通过尽可能地复制当前行为来实现.
  // 此apply的行为类似于其他语言中的"super".
  // 即使 valueOf() 不带参数, 其他的钩子可能会带有.
  return current.apply(this, arguments);
 }
}

从示例不难看出,我可以在某些条件下通过 apply() 方法调用函数原逻辑,某些条件执行我需要的新逻辑。

写个 demo 测试一下

// 重写Function的原型方法cache
Function.prototype.cache = function () {
  var _self = this;
  return function() {
 console.log('arguments', arguments);
 var key = arguments[0];
    if (cache.has(key)) {
      return cache.get(key)
    } else {
      return _self.apply(this, arguments)
    }
  }
}

定义 cache,当且仅当 key 为 1 时有值

var cache = {
  has: (key) => {
 if (key === 1) return true
 else return false
  },
  get: (key) => {
    return "cached value " + key
  }
}

定义测试方法

function request(key) {
 return 'value of ' + key
}

应用注入

request = request.cache()

执行一下

request(2)
"value of 2"
request(1)
"cached value 1"

看到结果按照预期输出,完美!

最后实现

项目引用了 memory-cache 作为基础缓存库,实现了相关的缓存功能。

simple-cache.js
const cache = require('memory-cache');
Function.prototype.cache = function (cachekey, time) {
  var _self = this;
  return function() {
 var key = cachekey(arguments);
    var value = cache.get(key);
    if (!value) {
      value = _self.apply(this, arguments)
  cache.put(key, value, time);
    }
    return value;
  }
}
var simpleCache = {
 cache: function(f, cacheKey, cacheTime) {
 return f.cache(cacheKey, cacheTime);
 }
}
module.exports = simpleCache
sample.js
const cache = require('simple-cache-z').cache;
function cachekey(args) {
  return args[0]
}
function request(key) {
  return (new Date()).getTime();
}
request = cache(request, cachekey, 5000);
console.log('request 1 ', request(1));
setTimeout(() => {
  console.log('request 2 ', request(2));
}, 1000)
setTimeout(()=> {
  console.log('request 1 ', request(1))
  console.log('request 1 ', request(1))
  console.log('request 1 ', request(1))
  console.log('request 2 ', request(2));
  console.log('request 2 ', request(2));
  console.log('request 2 ', request(2));
}, 2000);
setTimeout(()=> {
  console.log('request 1 ', request(1));
  console.log('request 1 ', request(1));
  console.log('request 1 ', request(1));
  console.log('request 2 ', request(2));
  console.log('request 2 ', request(2));
  console.log('request 2 ', request(2));
}, 10000);

输出结果

request 1  1563000551142
// 1000 ms
request 2  1563000552150
// 2000 ms
request 1  1563000551142
request 1  1563000551142
request 1  1563000551142
request 2  1563000552150
request 2  1563000552150
request 2  1563000552150
// 10000 ms
request 1  1563000561151
request 1  1563000561151
request 1  1563000561151
request 2  1563000561151
request 2  1563000561151
request 2  1563000561151

大功告成!

今日研究成果

事实证明方案可行,应用到我的项目中对执行效率和代码可读性的提升非常明显。

我已经把框架打成了包,上传到 npm 仓库 simple-cache-z ,可通过如下方式引用。

npm install --save simple-cache-z

用法和代码上传至 github 仓库,欢迎提交代码和 star:

https://github.com/auv1107/simple-cache-nodejs

总结

以上所述是小编给大家介绍的Node.js 实现简单的无侵入式缓存框架的方法,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
JS写的数字拼图小游戏代码[学习参考]
Oct 29 Javascript
Javascript 跨域访问解决方案
Feb 14 Javascript
浅析jQuery的链式调用之each函数
Dec 03 Javascript
js onload事件不起作用示例分析
Oct 09 Javascript
jquery实现实时改变网页字体大小、字体背景色和颜色的方法
Aug 05 Javascript
js窗口关闭提示信息(兼容IE和firefox)
Oct 23 Javascript
jQuery实现iframe父窗体和子窗体的相互调用
Jun 17 Javascript
使用do...while的方法输入一个月中所有的周日(实例代码)
Jul 22 Javascript
jQuery实现表格与ckeckbox的全选与单选功能
Nov 24 Javascript
基于JavaScript实现自动更新倒计时效果
Dec 19 Javascript
Vue.js事件处理器与表单控件绑定详解
Mar 20 Javascript
JS一分钟在github+Jekyll的博客中添加访问量功能的实现
Apr 03 Javascript
Vue中遍历数组的新方法实例详解
Jul 21 #Javascript
Vue项目中使用WebUploader实现文件上传的方法
Jul 21 #Javascript
jquery插件开发模式实例详解
Jul 20 #jQuery
JS回调函数原理与用法详解【附PHP回调函数】
Jul 20 #Javascript
JavaScript展开操作符(Spread operator)详解
Jul 20 #Javascript
JavaScript剩余操作符Rest Operator详解
Jul 20 #Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
Jul 20 #Javascript
You might like
phplot生成图片类用法详解
2015/01/06 PHP
PHP保留两位小数的几种方法
2019/07/24 PHP
基于php伪静态的实现方法解析
2020/07/31 PHP
ExtJs Excel导出并下载IIS服务器端遇到的问题
2011/09/16 Javascript
标题过长使用javascript按字节截取字符串
2014/04/24 Javascript
js小数运算出现多位小数如何解决
2015/10/08 Javascript
JavaScript 经典实例日常收集整理(常用经典)
2016/03/30 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
2016/11/09 Javascript
原生js获取left值和top值的三种方法
2017/08/02 Javascript
在Js页面通过POST传递参数跳转到新页面详解
2017/08/25 Javascript
JS常见DOM节点操作示例【创建 ,插入,删除,复制,查找】
2018/05/14 Javascript
jQuery发请求传输中文参数乱码问题的解决方案
2018/05/22 jQuery
jQuery设置下拉框显示与隐藏效果的方法分析
2019/09/15 jQuery
JS扁平化输出数组的2种方法解析
2019/09/17 Javascript
对layui中table组件工具栏的使用详解
2019/09/19 Javascript
Python3基础之函数用法
2014/08/13 Python
浅谈Python的Django框架中的缓存控制
2015/07/24 Python
Python变量和数据类型详解
2017/02/15 Python
Python实现翻转数组功能示例
2018/01/12 Python
纯python实现机器学习之kNN算法示例
2018/03/01 Python
关于不懂Chromedriver如何配置环境变量问题解决方法
2019/06/12 Python
python编写计算器功能
2019/10/25 Python
python实现逆滤波与维纳滤波示例
2020/02/26 Python
pytorch实现查看当前学习率
2020/06/24 Python
Django中的DateTimeField和DateField实现
2021/02/24 Python
请写出 float x 与"零值"比较的 if 语句
2016/01/04 面试题
计算机网络专业推荐信
2013/11/24 职场文书
财务管理个人自荐书范文
2013/11/24 职场文书
怎样写好自我鉴定
2013/12/04 职场文书
优秀经理获奖感言
2014/03/04 职场文书
冬季安全检查方案
2014/05/23 职场文书
贷款担保书
2015/01/20 职场文书
幼儿园中秋节活动总结
2015/03/23 职场文书
承诺书应该怎么写?
2019/09/10 职场文书
Go语言 go程释放操作(退出/销毁)
2021/04/30 Golang