Commonjs困惑二:如何理解require缓存?如何删除?
发布于 作者:苏南大叔 来源:程序如此灵动~苏南大叔再来描述commonjs
的困惑二,require
语句的缓存现象。首先澄清一下,require
语句缓存现象并非是commonjs
所特有的。其次,多次require
导致缓存现象,也并不是太常见的,并不是大范围的问题。
本文测试环境:node
。本文主要议题是:require
语句的缓存是什么,如何处理这种缓存。
require
语句缓存是什么?
这个require
语句缓存,是由node
自身的机制所引起的,并非commonjs
所特有的。主要表现在:在同一个文件里面,多次引用同一个模块的话,实际上除了第一次引用之外,其它引用都是缓存,读到的变量都很可能是个错误的值。
下面有个例子:module.js
:
var name = "苏南";
var age = 18;
var getAge = function () {
return age;
};
module.exports = {
name: name,
getAge: getAge,
};
test.js
:
var a = require("./module")
console.log(a.name)
a.name="苏南大叔"
console.log(a.name)
var a2 = require("./module") // 同一个模块
console.log(a2.name)
在这个例子中,可以看到第二次引用module
得到的a2
,它的name
属性居然是a
中的name
,随着a
的name
变化而变化。明明a
和a2
是不同的实例啊,但是由于require
缓存的存在,这个事情就变得扑朔迷离了。按理说,完全不相同的两个实例,变成了同一个实例。
如何删除require
语句缓存
这里说一下require
语句缓存的破解之法,下面的是个例子:
var a = require("./module")
console.log(a.name)
a.name="苏南大叔"
console.log(a.name)
delete require.cache[require.resolve("./module")]
var a2 = require("./module2")
console.log(a2.name)
其中核心代码是:
delete require.cache[require.resolve("./module")]
这个核心代码,所需要的参数是个绝对路径。但是,一般来说,大家写的都是相对路径,所以,这里需要个函数进行一下转化。
require.resolve()
还是,值得一提的是,这个参数还是个数组。所以,是可以批量传入多个要删除缓存的文件路径的,例如:
delete require.cache[require.resolve("./module"),require.resolve("./module2")]
最后,如果您需要一个简单有效的大范围攻击魔法,下面的代码是您需要的,并不需要制定路径。直接删除所有的require
缓存。
Object.keys(require.cache).forEach(function(key) {
delete require.cache[key];
})
相关链接
总结
苏南大叔个人认为:一般来说,大家并不会在同一个文件里面多次require
同一个模块。但是,并不排除这种可能性,如果真的这么做了,就要考虑到一个缓存的机制,需要在适当的时机,删除这个require
缓存,否则,就会出现认知上的偏差。
更多commonjs
文章,请参考苏南大叔的博客:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。