Nodejs 有没有办法取消 node.js 对 require 模块的缓存?

Nodejs 有没有办法取消 node.js 对 require 模块的缓存?

譬如我想用 express 写这样一个 router:

function (req, res) {
    try {
        var title        = req.param('title'),
            viewTemplate = 'path/to/template',
            config       = require('path/to/config') || {};

        res.render(viewTemplate, config);
    } catch (e) {
        // handleErr('400', res);
    }
};

它的功能是响应 ‘/:title’ URL, 用 ‘path/to/config’ 中的配置数据去渲染 ‘path/to/template’ 里的模板文件,返回页面。

调试的时候遇到一个有点麻烦的地方,就是修改了配置数据之后,必须重启服务器才能看到修改后的结果。

也就是 config = require('path/to/config') || {} 这个值因为 require 的时候模块缓存的存在,刷新页面的时候并不会动态去重新加载一次 ‘path/to/config.js’ 文件,导致这个文件的修改只能通过重启才能体现。

有没有方法可以取消 require 的时候的缓存呢?对我来说,如果可以在开发的时候取消这个,开发起来就方便很多了。

顺便,stackoverflow 上面貌似说不可能(http://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate)。期盼大牛现身辟谣。


16 回复

Nodejs 有没有办法取消 node.js 对 require 模块的缓存?

问题背景

假设你正在使用 Express 编写一个路由处理函数:

function (req, res) {
    try {
        var title        = req.param('title'),
            viewTemplate = 'path/to/template',
            config       = require('path/to/config') || {};

        res.render(viewTemplate, config);
    } catch (e) {
        // handleErr('400', res);
    }
}

这个路由的功能是响应 /:title URL,并使用 path/to/config 文件中的配置数据来渲染 path/to/template 模板文件。

在调试过程中,你发现了一个问题:每次修改了 path/to/config.js 文件后,必须重启服务器才能看到配置的更新。这是因为 Node.js 在 require 模块时会缓存模块,以提高性能。

解决方案

虽然 Node.js 的 require 缓存机制设计初衷是为了提升性能,但在某些场景下,如开发调试中,我们可能需要手动取消这种缓存。以下是几种解决方法:

方法一:删除缓存项

你可以通过手动删除 require.cache 中对应的缓存项来实现这一目的。

const fs = require('fs');
const path = require('path');

function reloadConfig(configPath) {
    const modulePath = path.resolve(configPath);
    if (modulePath in require.cache) {
        delete require.cache[modulePath];
    }
    return require(modulePath);
}

// 使用示例
function (req, res) {
    try {
        var title        = req.param('title'),
            viewTemplate = 'path/to/template',
            config       = reloadConfig('path/to/config') || {};

        res.render(viewTemplate, config);
    } catch (e) {
        // handleErr('400', res);
    }
}

在这个示例中,我们定义了一个 reloadConfig 函数,它接受一个路径参数并删除该路径对应的缓存项,然后重新 require 该模块。这样就可以确保每次调用时都能获取到最新的配置文件内容。

方法二:使用 module.parent.children

另一种方法是遍历 module.parent.children 数组,找到并删除对应的缓存项。

function reloadConfig(configPath) {
    const modulePath = require.resolve(configPath);
    for (let child of module.parent.children) {
        if (child.filename === modulePath) {
            module.parent.children.splice(module.parent.children.indexOf(child), 1);
        }
    }
    return require(modulePath);
}

这种方法同样可以确保每次调用时都能重新加载配置文件。

总结

通过上述方法,你可以在开发环境中取消 Node.js 的 require 缓存,从而实现实时查看配置文件的更新。不过请注意,在生产环境中,应避免频繁地清除缓存,以免影响性能。


你需要 nodemon 或者 supervisor 或者 grunt

要么就用fs读文件吧

嗯,在用 grunt,先试试看 谢谢啦!

貌似也不错,可以写成 json

不过果然是不能通过编码的方式来取消 require 的缓存吗?

代码上很简单

delete require.cache[‘path/to/config’] config = require(‘path/to/config’)

代码背后的东西不这么简单,比如说通知你其他的代码更新引用等等。如果只是配置的话应该还好

谢谢! 我看文档还是不熟啊

谢谢大牛!

我觉得你这样是走进误区了,require,cache是非常节省资源的设计,你那样说明你误用require了,既然需要config.js中的配置来渲染数据,为啥配置要频繁改动,如果config频繁改动为什么不反悔一个对象通过穿进去的参数动态改变配置呢!

代码热更新可以使用 bearcat

watch感觉不可靠…

delete require.cache[require.resolve(path)]

不能简单的直接取消 require 的缓存,因为有些模块在载入的时候会做一些初始化工作,如果 一刀切地 取消 require 的缓存,就会导致这些模块初始化多次,在实际使用的时候就会出问题。

另外,要实现代码热更新,编写程序的时候就必须为热更新而做很多改变,比如不能长期引用某个对象或函数,所有的东西都需要通过一个函数来动态返回最新的引用,然后再操作,总会另代码显得很怪,比如:

// 原来的使用方式
var my = require('./my_module');
my.doSomething1();
my.doSomething2();

// 新的使用方式 require(’./my_module’).doSomethig1(); require(’./my_module’).doSomethig2()

目前最完美稳定的解决方法是 重启进程!!!!

可以取消 Node.js 对 require 模块的缓存。你可以使用 delete require.cache 来手动删除模块缓存,从而实现每次请求时重新加载配置文件。

以下是示例代码:

const path = require('path');
const fs = require('fs');

function loadConfig(configPath) {
    delete require.cache[require.resolve(configPath)];
    return require(configPath);
}

function (req, res) {
    try {
        var title        = req.param('title'),
            viewTemplate = 'path/to/template',
            configPath   = 'path/to/config';

        var config = loadConfig(configPath);

        res.render(viewTemplate, config);
    } catch (e) {
        // handleErr('400', res);
    }
}

在这个示例中,我们定义了一个 loadConfig 函数来重新加载配置文件。每次调用 loadConfig 函数时,它会删除当前的缓存,并重新加载配置文件。

这种方法在开发过程中非常有用,因为它允许你在不重启服务器的情况下看到配置文件的更改。但在生产环境中,建议避免频繁地修改配置文件,以确保应用的稳定性和性能。

回到顶部