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多物体 任意值 链式 缓冲运动
Aug 10 Javascript
JS清除IE浏览器缓存的方法
Jul 26 Javascript
一些老手都不一定知道的JavaScript技巧
May 06 Javascript
jquery实现预览提交的表单代码分享
May 21 Javascript
javascript获取元素偏移量的方法有哪些
Jun 24 Javascript
ECMAScript中函数function类型
Jun 03 Javascript
jQuery平滑旋转幻灯片特效代码分享
Sep 07 Javascript
javascript定义类和类的实现实例详解
Dec 01 Javascript
jQuery读取XML文件的方法示例
Feb 03 Javascript
详解Javascript几种跨域方式总结
Feb 27 Javascript
JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】
Feb 21 Javascript
js实现经典贪吃蛇小游戏
Mar 19 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
了解咖啡雨林联盟认证 什么是雨林认证 雨林认证是什么意思
2021/03/05 新手入门
php中的一个中文字符串截取函数
2007/02/14 PHP
php数据结构与算法(PHP描述) 查找与二分法查找
2012/06/21 PHP
PHP根据两点间的经纬度计算距离
2014/10/31 PHP
php模拟post提交数据的方法
2015/02/12 PHP
php mysqli查询语句返回值类型实例分析
2016/06/29 PHP
PHP设计模式(八)装饰器模式Decorator实例详解【结构型】
2020/05/02 PHP
WordPress 插件——CoolCode使用方法与下载
2007/07/02 Javascript
Js获取事件对象代码
2010/08/05 Javascript
Javascript事件实例详解
2013/11/06 Javascript
基于jQuery和CSS3制作数字时钟附源码下载(jquery篇)
2015/11/24 Javascript
一款简单的jQuery图片标注效果附源码下载
2016/03/22 Javascript
深入浅析JavaScript函数前面的加号和叹号
2016/07/09 Javascript
js实现复选框的全选和取消全选效果
2017/01/03 Javascript
ng-repeat指令在迭代对象时的去重方法
2018/10/02 Javascript
Vue+Element ui 根据后台返回数据设置动态表头操作
2020/09/21 Javascript
使用Python内置的模块与函数进行不同进制的数的转换
2016/03/12 Python
在python环境下运用kafka对数据进行实时传输的方法
2018/12/27 Python
Python 多个图同时在不同窗口显示的实现方法
2019/07/07 Python
在django admin中添加自定义视图的例子
2019/07/26 Python
pytorch标签转onehot形式实例
2020/01/02 Python
Python递归实现打印多重列表代码
2020/02/27 Python
python3用urllib抓取贴吧邮箱和QQ实例
2020/03/10 Python
Jupyter打开图形界面并画出正弦函数图像实例
2020/04/24 Python
Python 使用生成器代替线程的方法
2020/08/04 Python
Python爬虫分析微博热搜关键词的实现代码
2021/02/22 Python
HTML5+CSS3 诱人的实例:3D立方体旋转动画实例
2016/12/30 HTML / CSS
详解快速开发基于 HTML5 网络拓扑图应用
2018/01/08 HTML / CSS
党的群众路线教育实践活动批评与自我批评
2014/02/16 职场文书
医疗器械售后服务承诺书
2014/05/21 职场文书
阳光体育活动实施方案
2014/05/25 职场文书
小学校长汇报材料
2014/08/20 职场文书
办公室岗位职责范本
2015/04/11 职场文书
大学生学生会工作总结2015
2015/05/26 职场文书
oracle表分区的概念及操作
2021/04/24 Oracle
Navicat连接MySQL错误描述分析
2021/06/02 MySQL