नोड.js की आवश्यकता () कैश - अमान्य करने के लिए संभव है?


325

नोड से। प्रलेखन:

पहली बार लोड किए जाने के बाद मॉड्यूल को कैश किया जाता है। इसका मतलब है (अन्य बातों के अलावा) कि आवश्यकता के लिए हर कॉल ('फू') को उसी वस्तु को वापस मिलेगा, यदि वह उसी फ़ाइल को हल करेगी।

क्या इस कैश को अमान्य करने का कोई तरीका है? यानी यूनिट टेस्टिंग के लिए, मैं चाहूंगा कि प्रत्येक टेस्ट किसी नई वस्तु पर काम किया जाए।


8
एनपीएम मॉड्यूल github.com/gajus/require-new
गजस

एक द्रष्टा के साथ एक और एनपीएम मॉड्यूल: npmjs.com/package/updated-require
जॉर्ज

आवश्यकता के उपयोग के बिना फ़ाइल सामग्री को कैश करना संभव है और इसे अलग-अलग
स्कोप्स के लिए उतारा गया है

जवाबों:


305

आप हमेशा किसी समस्या के बिना आवश्यकता के प्रविष्टि को सुरक्षित रूप से हटा सकते हैं, भले ही परिपत्र निर्भरता हो। क्योंकि जब आप हटाते हैं, तो आप केवल कैश्ड मॉड्यूल ऑब्जेक्ट का संदर्भ हटाते हैं, मॉड्यूल ऑब्जेक्ट ही नहीं, मॉड्यूल ऑब्जेक्ट GCed नहीं होगा क्योंकि परिपत्र निर्भरता के मामले में, इस मॉड्यूल ऑब्जेक्ट को संदर्भित करने वाली कोई वस्तु अभी भी है।

मान लीजिए आपके पास:

स्क्रिप्ट a.js:

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

और स्क्रिप्ट b.js:

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

जब तुम करोगे:

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

तुम्हे मिल जाएगा:

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

अब यदि आप अपना b.js संपादित करते हैं:

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

और करो:

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

तुम्हे मिल जाएगा:

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

===

यदि नोड सीधे चल रहा है तो उपरोक्त वैध है। हालांकि, अगर उन उपकरणों का उपयोग करना जिनके पास अपने स्वयं के मॉड्यूल कैशिंग सिस्टम हैं, जैसे कि जेस्ट , सही कथन होगा:

jest.resetModules();

2
क्या आप बता सकते हैं कि पहली बार { ... a: undefined}आवश्यकता b.jsहोने पर क्यों ? मैं बराबर की उम्मीद करूंगा 'a from a.js'
इरा

1
एक अपरिभाषित क्यों है?
जेफ पी चाको

4
उत्तर देर से, लेकिन जो मैं इकट्ठा करता हूं b[a]वह पहली बार अपरिभाषित है क्योंकि एक परिपत्र निर्भरता है। a.jsइसके b.jsबदले में आवश्यकता होती है a.jsa.jsअभी तक पूरी तरह से भरा हुआ नहीं है और exports.aइसे अभी तक परिभाषित नहीं किया गया है, इसलिए b.jsकुछ भी नहीं प्राप्त करें।
nik10110

किसी भी तरह से अगर मैं require.main.require(path)यहाँ वर्णित के रूप में उपयोग कर रहा हूँ ? stackoverflow.com/questions/10860244/…
फ्लिअन

186

यदि आप हमेशा अपने मॉड्यूल को फिर से लोड करना चाहते हैं, तो आप इस फ़ंक्शन को जोड़ सकते हैं:

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

और फिर requireUncached('./myModule')आवश्यकता के बजाय उपयोग करें ।


6
यह उस fs.watchपद्धति के साथ संयोजन में एकदम सही है जो फ़ाइल परिवर्तनों के लिए सुनता है।
ph3nx

2
जोखिम क्या है?
स्कार्पस

एक ही सवाल मेरे पास है, इस समाधान का उपयोग करने का जोखिम क्या है और स्वीकृत उत्तर नहीं है?
रोटिमी-बेस्ट

1
यह वास्तव में ऐसा ही है। कोड कैसे संरचित है, इसके आधार पर, जब आप इसे फिर से शुरू करने का प्रयास करते हैं तो चीजें दुर्घटनाग्रस्त हो सकती हैं। पूर्व। यदि मॉड्यूल सर्वर शुरू करता है, और एक पोर्ट को सुनता है। अगली बार जब आपको मॉड्यूल की आवश्यकता होगी, तो यह विफल हो जाएगा क्योंकि यह पोर्ट पहले से ही खोला गया है, और इसी तरह।
luff

133

हां, आप उस कैश का उपयोग कर सकते हैं, require.cache[moduleName]जहां moduleNameआप उस मॉड्यूल का नाम है जिसे आप एक्सेस करना चाहते हैं। कॉल करके प्रविष्टि को हटाने से वास्तविक फ़ाइल लोड delete require.cache[moduleName]होगी require

यह है कि आप मॉड्यूल से जुड़ी सभी कैश्ड फ़ाइलों को कैसे हटाएंगे:

/**
 * 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));
    }
};

उपयोग होगा:

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

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

चूंकि यह कोड समान रिज़ॉल्वर का उपयोग requireकरता है, बस आपको जो कुछ भी आवश्यकता होती है उसे निर्दिष्ट करें।


"यूनिक्स को अपने उपयोगकर्ताओं को बेवकूफ चीजें करने से रोकने के लिए नहीं बनाया गया था, क्योंकि यह उन्हें चतुर चीजें करने से भी रोक देगा।" - डग Gwyn

मुझे लगता है कि एक स्पष्ट अनछुए मॉड्यूल लोड करने के लिए एक तरीका होना चाहिए था।


17
+1 बस डौग के उद्धरण के लिए। मुझे किसी ऐसे व्यक्ति की ज़रूरत थी जिसे मैं भी
मानता

1
बहुत बढ़िया जवाब! यदि आप एक नोड को फिर से लोड करने के साथ एक नोड शुरू करना चाहते हैं, तो इस जिस्ट को सक्षम करें ।
gleitz

1
बहुत बढ़िया। मैं इसे require.uncacheफंक्शन में शामिल करूंगा । `` `// देखें github.com/joyent/node/issues/8266 Object.keys (मॉड्यूल.constructor._pathCache) .forEach (फ़ंक्शन (k) {if (k.indexOf (मॉड्यूलनाम)> 0) मॉड्यूल को हटाएं। अवरोधक ._पथकैच [के];}); `` `कहो कि आपको एक मॉड्यूल की आवश्यकता है, फिर उसे अनइंस्टॉल कर दिया, फिर उसी मॉड्यूल को फिर से इंस्टॉल किया लेकिन एक अलग संस्करण का उपयोग किया, जिसके पैकेज में एक अलग मुख्य स्क्रिप्ट है। ठीक है, अगली आवश्यकता विफल हो जाएगी क्योंकि वह मुख्य स्क्रिप्ट मौजूद नहीं है क्योंकि यह में कैश हैModule._pathCache
bentael

बकवास। मेरी टिप्पणी बहुत ही भयानक है। मैं इस टिप्पणी में बड़े करीने से कोड नहीं जोड़ सका और इसे संपादित करने में बहुत देर हो चुकी है, इसलिए मैंने जवाब दिया। @ बर्नके यदि आप अपने प्रश्न को कोड के छोटे स्निपेट को जोड़ने के लिए संपादित कर सकते हैंrequire.uncache
bentael

धन्यवाद @bentael, मैंने इसे अपने उत्तर में जोड़ दिया है।
बेन बर्के

39

इसके लिए एक सरल मॉड्यूल है ( परीक्षणों के साथ )

जबकि हम इस सटीक मुद्दा था परीक्षण हमारे कोड ( ताकि वे फिर से अपेक्षित एक ताजा राज्य में हो सकता है कैश की गई मॉड्यूल हटाना ) तो हम सब की समीक्षा की सुझाव विभिन्न StackOverflow प्रश्न और उत्तर पर लोगों की और एक साथ एक डाल सरल Node.js मॉड्यूल ( परीक्षण के साथ ):

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

जैसा कि आप उम्मीद करेंगे, दोनों प्रकाशित npm संकुल और स्थानीय रूप से परिभाषित मॉड्यूल के लिए काम करता है । विंडोज, मैक, लिनक्स, आदि।

स्थिति बनाएँ codecov.io कोड जलवायु स्थिरता निर्भरता की स्थिति निर्भरता की स्थिति

कैसे? ( उपयोग )

उपयोग बहुत सरल है:

इंस्टॉल

Npm से मॉड्यूल स्थापित करें:

npm install decache --save-dev

इसे अपने कोड में उपयोग करें:

// 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)

यदि आपके कोई प्रश्न हैं या अधिक उदाहरणों की आवश्यकता है, तो कृपया GitHub समस्या बनाएँ: https://github.com/dwyl/decache/issues


1
मैं इसे देख रहा हूं और परीक्षण करते समय इसका उपयोग करना मेरे लिए वास्तव में बहुत अच्छा लग रहा है ताकि मैं विशिष्ट परिस्थितियों में किसी मॉड्यूल को अनलोड और रीलोड कर सकूं, लेकिन दुर्भाग्य से मैं काम पर हूं और मेरी कंपनी जीपीएल लाइसेंस से दूर हो गई। मैं केवल इसे परीक्षण के लिए उपयोग करना चाहता हूं इसलिए मैं अभी भी इस पर विचार कर रहा हूं क्योंकि यह इतना उपयोगी लगता है।
मैट 9JD

@Matt_JD आपकी प्रतिक्रिया के लिए धन्यवाद। आप कौन सा लाइसेंस पसंद करेंगे?
नेल्सन

2
@Matt_JD हमने MIT को लाइसेंस अपडेट कर दिया है। अपने काम के साथ शुभकामनाएँ! :-)
नेल्सन

1
यह आश्चर्यजनक काम किया! इस रेपो को अभिनीत किया और इस उत्तर को उभार दिया।
१०

1
अत्यधिक अनुशंसा, आज के रूप में नवीनतम v14.2.0 पर ठीक चल रहा है
Thomazella

28

इस पार आने वाले किसी भी व्यक्ति के लिए, जो जेस्ट का उपयोग कर रहा है, क्योंकि जेस्ट अपने स्वयं के मॉड्यूल कैशिंग करता है, इसके लिए एक अंतर्निहित फ़ंक्शन है - बस सुनिश्चित jest.resetModulesरन उदा। आपके प्रत्येक परीक्षण के बाद:

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

सुझाए गए दूसरे उत्तर की तरह डिकैशे का उपयोग करने की कोशिश करने के बाद यह मिला । आभार एंथनी गर्वन ने माना

यहाँ समारोह प्रलेखन ।


1
इस नोट के लिए बहुत बहुत धन्यवाद!
mjgpy3

2
भगवान जब तक मैं यह पाया इससे पहले कि मैं प्रयोग किया .... धन्यवाद!
टियागो

16

समाधान का उपयोग करना है:

delete require.cache[require.resolve(<path of your script>)]

यहां उन लोगों के लिए कुछ बुनियादी स्पष्टीकरण खोजें, जो मेरे जैसे हैं, इसमें कुछ नया है:

मान लीजिए कि example.jsआपकी निर्देशिका की जड़ में एक डमी फ़ाइल है:

exports.message = "hi";
exports.say = function () {
  console.log(message);
}

फिर आपको require()यह पसंद है:

$ node
> require('./example.js')
{ message: 'hi', say: [Function] }

यदि आप इस तरह एक पंक्ति जोड़ते हैं example.js:

exports.message = "hi";
exports.say = function () {
  console.log(message);
}

exports.farewell = "bye!";      // this line is added later on

और कंसोल में जारी रखें, मॉड्यूल अपडेट नहीं किया गया है:

> require('./example.js')
{ message: 'hi', say: [Function] }

जब आप कश के उत्तरdelete require.cache[require.resolve()] में संकेत का उपयोग कर सकते हैं :

> delete require.cache[require.resolve('./example.js')]
true
> require('./example.js')
{ message: 'hi', say: [Function], farewell: 'bye!' }

इसलिए कैश को साफ किया जाता है और require()फ़ाइल की सामग्री को फिर से कैप्चर करता है, सभी वर्तमान मान लोड करता है।


IMHO यह सबसे उपयुक्त उत्तर है
पीयूष कटारिया

5

rewire इस उपयोग के मामले के लिए बहुत अच्छा है, आपको प्रत्येक कॉल के साथ एक नया उदाहरण मिलता है। नोड.जेएस इकाई परीक्षण के लिए आसान निर्भरता इंजेक्शन।

rewire मॉड्यूल में एक विशेष सेटर और गेट्टर जोड़ता है ताकि आप बेहतर इकाई परीक्षण के लिए उनके व्यवहार को संशोधित कर सकें। आप कर सकते हैं

अन्य मॉड्यूल या ग्लोबल्स के लिए मोक्स इंजेक्ट करें जैसे कि प्रक्रिया रिसाव निजी चर मॉड्यूल के भीतर चर को ओवरराइड करता है। rewire फ़ाइल लोड नहीं करता है और नोड की आवश्यकता तंत्र का अनुकरण करने के लिए सामग्री को बाहर निकालता है। वास्तव में यह मॉड्यूल को लोड करने के लिए नोड की अपनी आवश्यकता का उपयोग करता है। इस प्रकार आपका मॉड्यूल आपके परीक्षण वातावरण में ठीक वैसा ही व्यवहार करता है जैसा कि नियमित परिस्थितियों में (आपके संशोधनों को छोड़कर)।

सभी कैफीन-एडिक्ट्स के लिए अच्छी खबर: कॉफी-स्क्रिप्ट के साथ भी काम करता है। ध्यान दें कि इस मामले में CoffeeScript को आपकी निर्भरता में सूचीबद्ध करने की आवश्यकता है।


4

मैं एक और लाइन के उत्तर को जोड़ना चाहूंगा और पैरामीटर नाम बदलूंगा:

function requireCached(_module){
    var l = module.children.length;
    for (var i = 0; i < l; i++)
    {
        if (module.children[i].id === require.resolve(_module))
        {
            module.children.splice(i, 1);
            break;
        }
    }
    delete require.cache[require.resolve(_module)];
    return require(_module)
}

तो यह सबमॉड्यूल्स में कार्य करने के लिए है? अच्छा! मॉड्यूल को हटाने का एक छोटा तरीका है। चिल्ड्रेन सरणी एक फिल्टर फ़ंक्शन का उपयोग करके है: मॉड्यूल.children = मॉड्यूल.children.filter (फ़ंक्शन (बच्चे) {return child.id! == आवश्यकता.resolve (_mindule)}); ;
luff

4

हां, आप कैश को अमान्य कर सकते हैं।

कैश को आवश्यकता के अनुसार एक वस्तु में संग्रहीत किया जाता है। जिसे कैश कहा जाता है जिसे आप सीधे फाइलनाम के अनुसार एक्सेस कर सकते हैं (उदाहरण के लिए - जिसके /projects/app/home/index.jsविपरीत ./homeआप एक require('./home')बयान में उपयोग करेंगे )।

delete require.cache['/projects/app/home/index.js'];

हमारी टीम ने निम्नलिखित मॉड्यूल को उपयोगी पाया है। मॉड्यूल के कुछ समूहों को अमान्य करने के लिए।

https://www.npmjs.com/package/node-resource


3

मैं एक उत्तर की टिप्पणी में बड़े करीने से कोड नहीं जोड़ सका। लेकिन मैं @ बार्क के जवाब का उपयोग करूंगा और फिर इसे फंक्शन में जोड़ूंगा require.uncache

    // see https://github.com/joyent/node/issues/8266
    // use in it in @Ben Barkay's require.uncache function or along with it. whatever
    Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
        if ( cacheKey.indexOf(moduleName) > -1 ) {
            delete module.constructor._pathCache[ cacheKey ];
        }
    }); 

मान लें कि आपको एक मॉड्यूल की आवश्यकता है, फिर उसे अनइंस्टॉल कर दिया, फिर उसी मॉड्यूल को फिर से इंस्टॉल किया, लेकिन एक अलग संस्करण का उपयोग किया, जिसके पैकेज में एक अलग मुख्य स्क्रिप्ट है। इसके अलावा, अगली आवश्यकता विफल हो जाएगी क्योंकि वह मुख्य स्क्रिप्ट मौजूद नहीं है क्योंकि यह कैश है Module._pathCache


3

मैं 'अमान्य' से आपके तात्पर्य का 100% निश्चित नहीं हूं, लेकिन आप requireकैश को साफ़ करने के लिए कथनों के ऊपर निम्नलिखित जोड़ सकते हैं :

Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })

@ Dancrumb की टिप्पणी से यहाँ लिया गया


2

requireUncached रिश्तेदार पथ के साथ: 🔥

const requireUncached = require => module => {
  delete require.cache[require.resolve(module)];
  return require(module);
};

module.exports = requireUncached;

सापेक्ष पथ के साथ अपेक्षित आह्वान:

const requireUncached = require('../helpers/require_uncached')(require);
const myModule = requireUncached('./myModule');

1

दो चरण प्रक्रिया का पालन करना मेरे लिए पूरी तरह से काम कर रहा है।

Modelफ़ाइल बदलने के बाद यानी 'mymodule.js'डायनामिकली, आपको पहले मॉडल में प्री- कम्पोज्ड मॉडल को डिलीट करना होगा, फिर आवश्यकता-पुनः लोड का उपयोग करके इसे फिर से लोड करना होगा

Example:
        // Delete mongoose model
        delete mongoose.connection.models[thisObject.singular('mymodule')]

        // Reload model
        var reload = require('require-reload')(require);
        var entityModel = reload('./mymodule.js');

0

यदि यह यूनिट परीक्षणों के लिए है, तो उपयोग करने के लिए एक और अच्छा उपकरण प्रॉक्सीक्वायर है । हर बार जब आप मॉड्यूल को प्रॉक्सी करते हैं, तो यह मॉड्यूल कैश को अमान्य कर देगा और एक नया कैश करेगा। यह आपको उस फ़ाइल द्वारा आवश्यक मॉड्यूल को संशोधित करने की भी अनुमति देता है जिसे आप परीक्षण कर रहे हैं।


0

मैंने लोड करने के बाद कैश से मॉड्यूल को हटाने के लिए एक छोटा मॉड्यूल बनाया। अगली बार आवश्यक होने पर यह मॉड्यूल के पुनर्मूल्यांकन को मजबूर करता है। Https://github.com/bahmutov/require-and-forget देखें

// random.js
module.exports = Math.random()
const forget = require('require-and-forget')
const r1 = forget('./random')
const r2 = forget('./random')
// r1 and r2 will be different
// "random.js" will not be stored in the require.cache

पुनश्च: आप "स्व-विनाश" को भी मॉड्यूल में डाल सकते हैं। देखHttps://github.com/bahmutov/unload-me

PSS: नोड के साथ अधिक ट्रिक्स की आवश्यकता मेरे https://glebbahmutov.com/blog/hacking-node-request/ में है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.