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 21 Javascript
jQuery 使用手册(六)
Sep 23 Javascript
JavaScript实现节点的删除与序号重建实例
Aug 05 Javascript
基于jQuery实现的向下滑动二级菜单效果代码
Aug 31 Javascript
JavaScript实现Java中Map容器的方法
Oct 09 Javascript
使用jquery判断一个元素是否含有一个指定的类(class)实例
Feb 12 Javascript
从零学习node.js之mysql数据库的操作(五)
Feb 24 Javascript
js实现字符全排列算法的简单方法
May 01 Javascript
详解vue中组件参数
Jul 09 Javascript
vue实现点击追加选中样式效果
Nov 01 Javascript
JavaScript控制台的更多功能
Apr 28 Javascript
小程序实现筛子抽奖
May 26 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
星际初学者游戏中永远要做的事
2020/03/04 星际争霸
在wamp集成环境下升级php版本(实现方法)
2013/07/01 PHP
PHP对文件进行加锁、解锁实例
2015/01/23 PHP
php array_key_exists() 与 isset() 的区别
2016/10/24 PHP
PHP类的自动加载与命名空间用法实例分析
2020/06/05 PHP
jQuery Dialog 弹出层对话框插件
2010/08/09 Javascript
JavaScript中使用正则匹配多条,且获取每条中的分组数据
2010/11/30 Javascript
jQuery动态显示和隐藏datagrid中的某一列的方法
2013/12/11 Javascript
node.js操作mongodb学习小结
2015/04/25 Javascript
js字符串操作方法实例分析
2015/05/06 Javascript
JS+CSS实现仿msn风格选项卡效果代码
2015/10/22 Javascript
JavaScript数据存储 Cookie篇
2016/07/02 Javascript
Javascript6中字符串的四个新用法分享
2016/09/11 Javascript
Bootstrap基本样式学习笔记之表格(2)
2016/12/07 Javascript
基于JS实现限时抢购倒计时间表代码
2017/05/09 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
Vue2路由动画效果的实现代码
2017/07/10 Javascript
快速解决brew安装特定版本flow的问题
2018/05/17 Javascript
js如何实现元素曝光上报
2019/08/07 Javascript
layui的面包屑或者表单不显示的解决方法
2019/09/05 Javascript
[00:48]食人魔魔法师至宝“金鹏之幸”全新模型和自定义特效展示
2019/12/19 DOTA
Python 检查数组元素是否存在类似PHP isset()方法
2014/10/14 Python
通过数据库向Django模型添加字段的示例
2015/07/21 Python
浅析AST抽象语法树及Python代码实现
2016/06/06 Python
基于python 字符编码的理解
2017/09/02 Python
Python任务调度模块APScheduler使用
2020/04/15 Python
Keras 快速解决OOM超内存的问题
2020/06/11 Python
关于HTML5 Placeholder新标签低版本浏览器下不兼容的问题分析及解决办法
2016/01/27 HTML / CSS
HTML5拍照和摄像机功能实战详解
2019/01/24 HTML / CSS
清华大学自主招生自荐信
2014/01/29 职场文书
公司晚会主持词
2014/03/22 职场文书
社区学习雷锋活动总结
2014/04/25 职场文书
公司总经理岗位职责范本
2014/08/15 职场文书
2014教师党员自我评议总结
2014/09/19 职场文书
群众路线个人自我剖析材料
2014/10/07 职场文书
Python中npy和mat文件的保存与读取
2022/04/24 Python