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 相关文章推荐
jquery实现的元素的left增加N像素 鼠标移开会慢慢的移动到原来的位置
Mar 21 Javascript
jquery遍历checkbox的注意事项说明
Feb 21 Javascript
zeroclipboard 单个复制按钮和多个复制按钮的实现方法
Jun 14 Javascript
JS+CSS实现仿雅虎另类滑动门切换效果
Oct 13 Javascript
javascript倒计时效果实现
Nov 12 Javascript
JavaScript该如何学习 怎样轻松学习JavaScript
Jun 12 Javascript
Vue.extend构造器的详解
Jul 17 Javascript
jQuery扇形定时器插件pietimer使用方法详解
Jul 18 jQuery
实例详解Node.js 函数
Jun 10 Javascript
react写一个select组件的实现代码
Apr 03 Javascript
javascript 函数的暂停和恢复实例详解
Apr 25 Javascript
javascript实现获取中文汉字拼音首字母
May 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
图象函数中的中文显示
2006/10/09 PHP
关于使用key/value数据库redis和TTSERVER的心得体会
2013/06/28 PHP
分享微信扫码支付开发遇到问题及解决方案-附Ecshop微信支付插件
2015/08/23 PHP
PHP实现浏览器中直接输出图片的方法示例
2018/03/14 PHP
js 图片缩放(按比例)控制代码
2009/05/27 Javascript
js统计页面的来访次数实现代码
2014/05/09 Javascript
jQuery中insertAfter()方法用法实例
2015/01/08 Javascript
Angularjs 滚动加载更多数据
2016/03/17 Javascript
jQuery中的each()详细介绍(推荐)
2016/05/25 Javascript
Vue组件BootPage实现简单的分页功能
2016/09/12 Javascript
vue实现手机号码抽奖上下滚动动画示例
2017/10/18 Javascript
js中bool值的转换及“&&”、“||”、 “!!”详解
2017/12/21 Javascript
浅谈vue单一组件下动态修改数据时的全部重渲染
2018/03/01 Javascript
详解mpvue中使用vant时需要注意的onChange事件的坑
2019/05/16 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
从零学python系列之数据处理编程实例(一)
2014/05/22 Python
Python中的自定义函数学习笔记
2014/09/23 Python
简单介绍Python的Django框架加载模版的方式
2015/07/20 Python
Django 添加静态文件的两种实现方法(必看篇)
2017/07/14 Python
Python实现利用最大公约数求三个正整数的最小公倍数示例
2017/09/30 Python
python topN 取最大的N个数或最小的N个数方法
2018/06/04 Python
Python3.5以上版本lxml导入etree报错的解决方案
2019/06/26 Python
使用python的turtle绘画滑稽脸实例
2019/11/21 Python
如何使用python切换hosts文件
2020/04/29 Python
PHP基于phpqrcode类库生成二维码过程解析
2020/05/28 Python
详解通过变换矩阵实现canvas的缩放功能
2019/01/14 HTML / CSS
HTML5中使用postMessage实现两个网页间传递数据
2016/06/22 HTML / CSS
你的自行车健身专家:FaFit24
2016/11/16 全球购物
英国票务网站:Ticketmaster英国
2018/08/27 全球购物
给水工程专业毕业生自荐信
2014/01/28 职场文书
酒店总经理助理职责
2014/02/12 职场文书
高考励志标语
2014/06/05 职场文书
汽车专业求职信
2014/06/05 职场文书
纪检干部个人对照检查材料
2014/09/23 职场文书
Go语言实现一个简单的并发聊天室的项目实战
2022/03/18 Golang
我国拿下天问一号火星着陆区附近 22 个地理实体命名:平乐、西柏坡、古田、漠河等
2022/04/29 数码科技