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实现的网页颜色代码表全集
Jul 17 Javascript
对 lightbox JS 图片控件进行了一下改造, 使其他支持复杂的图片说明
Mar 20 Javascript
javascript数字格式化通用类 accounting.js使用
Aug 24 Javascript
基于JQuery 选择器使用说明介绍
Apr 18 Javascript
js调试工具console.log()方法查看js代码的执行情况
Aug 08 Javascript
javascript实现框架高度随内容改变的方法
Jul 23 Javascript
jQuery简单实现上下,左右滑动的方法
Jun 01 Javascript
JQuery validate 验证一个单独的表单元素实例
Feb 17 Javascript
浅析Vue.js 中的条件渲染指令
Nov 19 Javascript
vue实现记事本功能
Jun 26 Javascript
JS删除数组指定值常用方法详解
Jun 04 Javascript
ES11屡试不爽的新特性,你用上了几个
Oct 21 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
PHP中创建并处理图象
2006/10/09 PHP
IIS6.0 开启Gzip方法及PHP Gzip函数分享
2014/06/08 PHP
thinkPHP+PHPExcel实现读取文件日期的方法(含时分秒)
2016/07/07 PHP
基于jQuery中对数组进行操作的方法
2013/04/16 Javascript
怎么选择Javascript框架(Javascript Framework)
2013/11/22 Javascript
将中国标准时间转换成标准格式的代码
2014/03/20 Javascript
JavaScript异步回调的Promise模式封装实例
2014/06/07 Javascript
判断字符串的长度(优化版)中文占两个字符
2014/10/30 Javascript
Javascript中的几种URL编码方法比较
2015/01/23 Javascript
在JavaScript中使用NaN值的方法
2015/06/05 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
jQuery基于cookie实现换肤功能实例
2017/10/14 jQuery
vue 中动态绑定class 和 style的方法代码详解
2018/06/01 Javascript
微信小程序纯文本实现@功能
2020/04/08 Javascript
[46:47]2014 DOTA2国际邀请赛中国区预选赛 DT VS HGT
2014/05/22 DOTA
[01:21]DOTA2周边文化主题展 神秘商店火热开售
2017/07/30 DOTA
Python中asyncore异步模块的用法及实现httpclient的实例
2016/06/28 Python
python中redis的安装和使用
2016/12/04 Python
python实现简单登陆系统
2018/10/18 Python
Python遍历文件夹 处理json文件的方法
2019/01/22 Python
Python使用itchat模块实现群聊转发,自动回复功能示例
2019/08/26 Python
使用OpCode绕过Python沙箱的方法详解
2019/09/03 Python
tensorflow实现在函数中用tf.Print输出中间值
2020/01/21 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
2020/02/07 Python
安装完Python包然后找不到模块的解决步骤
2020/02/13 Python
Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)
2021/02/22 Python
在线服装零售商:SheIn
2016/07/22 全球购物
小米旗下精品生活电商平台:小米有品
2018/12/18 全球购物
教师党员思想汇报
2014/01/06 职场文书
《手指教学》反思
2014/02/14 职场文书
四下基层实施方案
2014/03/28 职场文书
数控机床专业自荐信
2014/05/19 职场文书
2015年食品安全工作总结
2015/05/15 职场文书
大学同学聚会感言
2015/07/30 职场文书
redis不能访问本机真实ip地址的解决方案
2021/07/07 Redis
JavaScript中MutationObServer监听DOM元素详情
2021/11/27 Javascript