385 Stimmen

node.js require() cache - möglich, ungültig zu machen?

Aus der node.js-Dokumentation:

Module werden nach dem ersten Laden zwischengespeichert. Das bedeutet (unter anderem), dass bei jedem Aufruf von require('foo') genau das gleiche Objekt zurückgegeben wird, wenn es in dieselbe Datei aufgelöst wird.

Gibt es eine Möglichkeit, diesen Cache ungültig zu machen? d.h. für Unit-Tests möchte ich, dass jeder Test auf ein neues Objekt arbeitet.

358voto

kaisa1028 Punkte 3686

Sie können einen Eintrag in require.cache immer problemlos löschen, auch wenn es zirkuläre Abhängigkeiten gibt. Da Sie beim Löschen nur einen Verweis auf das zwischengespeicherte Modulobjekt und nicht das Modulobjekt selbst löschen, wird das Modulobjekt nicht überprüft, da im Falle von zirkulären Abhängigkeiten immer noch ein Objekt vorhanden ist, das auf dieses Modulobjekt verweist.

Angenommen, Sie haben:

Skript a.js:

var b=require('./b.js').b;
exports.a='a from a.js';
exports.b=b;

y Skript b.js:

var a=require('./a.js').a;
exports.b='b from b.js';
exports.a=a;

wenn Sie es tun:

var a=require('./a.js')
var b=require('./b.js')

erhalten Sie:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js', a: undefined }

Wenn Sie nun Ihre b.js bearbeiten:

var a=require('./a.js').a;
exports.b='b from b.js. changed value';
exports.a=a;

und tun:

delete require.cache[require.resolve('./b.js')]
b=require('./b.js')

erhalten Sie:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
  a: 'a from a.js' }

\===

Das oben Gesagte gilt, wenn node.js direkt ausgeführt wird. Wenn Sie jedoch Tools verwenden, die über ein eigenes Modul-Caching-System verfügen, wie z. B. scherzen wäre die richtige Aussage:

jest.resetModules();

250voto

luff Punkte 3154

Wenn Sie Ihr Modul immer wieder neu laden wollen, können Sie diese Funktion hinzufügen:

function requireUncached(module) {
    delete require.cache[require.resolve(module)];
    return require(module);
}

und verwenden Sie dann requireUncached('./myModule') anstelle von require.

140voto

Ben Barkay Punkte 5265

Ja, Sie können auf den Cache über require.cache[moduleName] donde moduleName ist der Name des Moduls, auf das Sie zugreifen möchten. Löschen eines Eintrags durch Aufruf von delete require.cache[moduleName] wird verursachen require um die aktuelle Datei zu laden.

Auf diese Weise können Sie alle mit dem Modul verknüpften Cache-Dateien entfernen:

/**
 * Removes a module from the cache
 */
function purgeCache(moduleName) {
    // Traverse the cache looking for the files
    // loaded by the specified module name
    searchCache(moduleName, function (mod) {
        delete require.cache[mod.id];
    });

    // Remove cached paths to the module.
    // Thanks to @bentael for pointing this out.
    Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
        if (cacheKey.indexOf(moduleName)>0) {
            delete module.constructor._pathCache[cacheKey];
        }
    });
};

/**
 * Traverses the cache to search for all the cached
 * files of the specified module name
 */
function searchCache(moduleName, callback) {
    // Resolve the module identified by the specified name
    var mod = require.resolve(moduleName);

    // Check if the module has been resolved and found within
    // the cache
    if (mod && ((mod = require.cache[mod]) !== undefined)) {
        // Recursively go over the results
        (function traverse(mod) {
            // Go over each of the module's children and
            // traverse them
            mod.children.forEach(function (child) {
                traverse(child);
            });

            // Call the specified callback providing the
            // found cached module
            callback(mod);
        }(mod));
    }
};

Die Verwendung wäre:

// Load the package
var mypackage = require('./mypackage');

// Purge the package from cache
purgeCache('./mypackage');

Da dieser Code denselben Resolver verwendet require tut, geben Sie einfach an, was Sie für require tun würden.


"Unix wurde nicht entwickelt, um seine Benutzer davon abzuhalten, dumme Dinge zu tun, wie denn das würde sie auch davon abhalten, kluge Dinge zu tun." - Doug Gwyn

Ich denke, dass es debe eine Möglichkeit zum expliziten Laden von nicht zwischengespeicherten Modulen gewesen sein.

45voto

nelsonic Punkte 28925

Es gibt eine Einfaches Modul dafür ( mit Tests )

Wir hatten genau dieses Problem, als wir Testen unser Code ( zwischengespeicherte Module zu löschen, damit sie in einem neuen Zustand erneut angefordert werden können ), also haben wir alle Vorschläge von Menschen auf den verschiedenen StackOverflow Fragen & Antworten und stellte eine einfach node.js-Modul ( mit Tests ):

https://www.npmjs.com/package/ decache

Wie zu erwarten, funktioniert das für beide veröffentlichte npm-Pakete und vor Ort definierte Module. Windows, Mac, Linux, etc.

Build Status codecov.io Code Climate maintainability Dependencies Status devDependencies Status

Wie? ( Verwendung )

Die Verwendung ist ziemlich einfach:

installieren

Installieren Sie das Modul von npm:

npm install decache --save-dev

Verwenden Sie es in Ihrem Code:

// require the decache module:
const decache = require('decache');

// require a module that you wrote"
let mymod = require('./mymodule.js');

// use your module the way you need to:
console.log(mymod.count()); // 0   (the initial state for our counter is zero)
console.log(mymod.incrementRunCount()); // 1

// delete the cached module:
decache('./mymodule.js');

//
mymod = require('./mymodule.js'); // fresh start
console.log(mymod.count()); // 0   (back to initial state ... zero)

Wenn Sie Fragen haben oder weitere Beispiele benötigen, erstellen Sie bitte ein GitHub-Problem: https://github.com/dwyl/decache/issues

31voto

Tim Malone Punkte 3241

Für alle, die auf dieses Problem stoßen und Jest verwenden: Da Jest sein eigenes Modul-Caching durchführt, gibt es eine eingebaute Funktion dafür - stellen Sie einfach sicher, dass jest.resetModules läuft z. B. nach jedem Ihrer Tests:

afterEach( function() {
  jest.resetModules();
});

Dies fand ich, nachdem ich versucht hatte, die decache wie in einer anderen Antwort vorgeschlagen. Dank an Anthony Garvan .

Dokumentation der Funktion aquí .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X