Node.js 實(shí)現(xiàn)簡(jiǎn)單的無(wú)侵入式緩存框架的方法
前言
python 的flask.ext.cache 通過(guò)注解這樣對(duì)方法返回結(jié)果進(jìn)行緩存:
@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)
這類(lèi)實(shí)現(xiàn)方式對(duì)業(yè)務(wù)邏輯沒(méi)有絲毫的侵入性,非常之優(yōu)雅。
最近在做 Node.js 地項(xiàng)目,然而 js ES 7 之前都不支持注解,目前見(jiàn)到的緩存框架雖然在 API 設(shè)計(jì)上都很簡(jiǎn)潔、很有想法。
可是痛點(diǎn)在于它們都是侵入式的,需要在業(yè)務(wù)邏輯代碼中插入緩存邏輯,這些方式很不優(yōu)雅。
正題
今天花點(diǎn)時(shí)間研究下js有沒(méi)有辦法,以比較優(yōu)雅地方法實(shí)現(xiàn)緩存。
我對(duì)緩存框架的訴求:
- 不對(duì)原方法進(jìn)行更改
- 能實(shí)現(xiàn)對(duì)不同參數(shù)地緩存
- 支持緩存時(shí)間
我了解到的 js 能力:
- 隱藏參數(shù)arguments可以獲取參數(shù)列表
- prototype 可用來(lái)重寫(xiě)覆蓋原方法
可行性?
看了看 prototype 文檔
直覺(jué)告訴我看起來(lái)可行,以下是官方的說(shuō)明:
當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),調(diào)用的參數(shù)被保留在類(lèi)似數(shù)組 "變量" 的參數(shù)中。例如, 在調(diào)用 "myFn (a、b、c)"時(shí), 在myFn 的主體內(nèi)的參數(shù)將包含 3個(gè)類(lèi)似數(shù)組的元素對(duì)應(yīng)于 (a、b、c)。 使用鉤子修改原型時(shí),只需通過(guò)調(diào)用該函數(shù)的 apply (),將 this 與參數(shù) (調(diào)用狀態(tài)) 傳遞給當(dāng)前行為。這種模式可以用于任何原型,如 Node.prototype、 Function.prototype 等.
var current = Object.prototype.valueOf;
// 由于我的屬性 "-prop-value"是交叉性的, 并不總是
// 在同一個(gè)原型鏈上,我想要修改 Object.prototype:
Object.prototype.valueOf = function() {
if (this.hasOwnProperty('-prop-value')) {
return this['-prop-value'];
} else {
// 它看起來(lái)不像我的對(duì)象之一,因此,讓我們退回到
// 默認(rèn)行為,通過(guò)盡可能地復(fù)制當(dāng)前行為來(lái)實(shí)現(xiàn).
// 此apply的行為類(lèi)似于其他語(yǔ)言中的"super".
// 即使 valueOf() 不帶參數(shù), 其他的鉤子可能會(huì)帶有.
return current.apply(this, arguments);
}
}
從示例不難看出,我可以在某些條件下通過(guò) apply() 方法調(diào)用函數(shù)原邏輯,某些條件執(zhí)行我需要的新邏輯。
寫(xiě)個(gè) demo 測(cè)試一下
// 重寫(xiě)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,當(dāng)且僅當(dāng) key 為 1 時(shí)有值
var cache = {
has: (key) => {
if (key === 1) return true
else return false
},
get: (key) => {
return "cached value " + key
}
}
定義測(cè)試方法
function request(key) {
return 'value of ' + key
}
應(yīng)用注入
request = request.cache()
執(zhí)行一下
request(2) "value of 2" request(1) "cached value 1"
看到結(jié)果按照預(yù)期輸出,完美!
最后實(shí)現(xiàn)
項(xiàng)目引用了 memory-cache 作為基礎(chǔ)緩存庫(kù),實(shí)現(xiàn)了相關(guān)的緩存功能。
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);
輸出結(jié)果
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
大功告成!
今日研究成果
事實(shí)證明方案可行,應(yīng)用到我的項(xiàng)目中對(duì)執(zhí)行效率和代碼可讀性的提升非常明顯。
我已經(jīng)把框架打成了包,上傳到 npm 倉(cāng)庫(kù) simple-cache-z ,可通過(guò)如下方式引用。
npm install --save simple-cache-z
用法和代碼上傳至 github 倉(cāng)庫(kù),歡迎提交代碼和 star:
https://github.com/auv1107/simple-cache-nodejs
總結(jié)
以上所述是小編給大家介紹的Node.js 實(shí)現(xiàn)簡(jiǎn)單的無(wú)侵入式緩存框架的方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!
相關(guān)文章
nodejs版本過(guò)高導(dǎo)致vue2版本的項(xiàng)目無(wú)法正常啟動(dòng)的解決方案
這篇文章主要給大家介紹了關(guān)于nodejs版本過(guò)高導(dǎo)致vue2版本的項(xiàng)目無(wú)法正常啟動(dòng)的解決方案,本文小編給大家詳細(xì)介紹了如何解決這個(gè)問(wèn)題,如有遇到同樣問(wèn)題的朋友可以參考下2023-11-11
開(kāi)箱即用的Node.js+Mysql模塊封裝實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了開(kāi)箱即用的Node.js+Mysql模塊封裝實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Ubuntu 16.04 64位中搭建Node.js開(kāi)發(fā)環(huán)境教程
如果想要在Ubuntu 16.04上安裝Node.js的話,這篇文章對(duì)你來(lái)說(shuō)肯定很重要。Node.js從本質(zhì)上來(lái)說(shuō)就是一個(gè)運(yùn)行在服務(wù)端上的封裝好了輸入輸出流的javascript程序。本文給大家詳細(xì)介紹了在Ubuntu 16.04 64位搭建Node.js開(kāi)發(fā)環(huán)境的步驟,有需要的朋友們可以參考學(xué)習(xí)。2016-10-10
Node.js+Express+Vue+MySQL+axios的項(xiàng)目搭建全過(guò)程
這篇文章主要介紹了Node.js+Express+Vue+MySQL+axios的項(xiàng)目搭建全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
詳解nodejs微信公眾號(hào)開(kāi)發(fā)——4.自動(dòng)回復(fù)各種消息
這篇文章主要介紹了詳解nodejs微信公眾號(hào)開(kāi)發(fā)——4.自動(dòng)回復(fù)各種消息,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
node管理統(tǒng)計(jì)文件大小并顯示目錄磁盤(pán)空間狀態(tài)從零實(shí)現(xiàn)
這篇文章主要為大家介紹了node管理統(tǒng)計(jì)文件大小并顯示目錄磁盤(pán)空間狀態(tài)的從零實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
修改node.js默認(rèn)的npm安裝目錄實(shí)例
今天小編就為大家分享一篇修改node.js默認(rèn)的npm安裝目錄實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
node.js中實(shí)現(xiàn)GET和POST請(qǐng)求的代碼示例
在很多場(chǎng)景中,我們的服務(wù)器都需要跟用戶(hù)的瀏覽器打交道,如發(fā)送驗(yàn)證碼、登錄表單提交,請(qǐng)求服務(wù)器數(shù)據(jù)一般都使用GET請(qǐng)求,表單提交到服務(wù)器一般都使用POST請(qǐng)求,本文詳細(xì)介紹了在Node.js中如何處理GET和POST請(qǐng)求,需要的朋友可以參考下2024-12-12
詳解Nodejs中自動(dòng)化瀏覽器操作神器Puppeteer的使用
Puppeteer是一個(gè)JavaScript庫(kù),它提供了一種方式來(lái)通過(guò)DevTools協(xié)議控制無(wú)頭瀏覽器,本文主要為大家介紹了Puppeteer的主要特性和使用方法,感興趣的可以了解下2024-01-01

