Si prega di spiegare il controllo delle versioni degli oggetti nel sistema del modulo nodejs

2 risposte

5

Penso che il pezzo critico che ti manca sia che il risultato di require("foo") sia sempre lo stesso oggetto . Considera questo esempio REPL:

> var myHttpModule = require("http")
{ ... }
> myHttpModule.someNewProperty = "someValue"
'someValue'
> require("http").someNewProperty
'someValue'

La seconda chiamata a require("http") non ha ricreato il modulo http - ha convocato il modulo solo http esistente nell'ambiente di esecuzione corrente di Node, che era stato modificato sulla riga precedente.

Quindi, nel tuo esempio, c'è solo un modulo Alpha. Quando Beta e Gamma chiamano require("alpha") , ottengono ciascuno lo stesso riferimento all'oggetto singleton del modulo Alpha univoco.

(O, per essere perfettamente precisi, stanno ottenendo lo stesso riferimento al valore exports del modulo Alpha. require crea a Module object, ma restituisce solo la proprietà exports di quel modulo. Se al momento non comprendi completamente la distinzione, non è un grosso problema.)

Dietro le quinte: cosa succede realmente con require nella cache?

La prima volta che usi require per includere un modulo, il nodo esegue effettivamente il codice in quel modulo. Il modulo risultante è memorizzato in require.cache . I successivi tentativi di caricare il modulo con require verificano innanzitutto un oggetto modulo già caricato in require.cache . ( Nota: moduli Node integrati nativi dell'ambiente come http sono eccezioni in quanto non usano require.cache - dovrai testare il mio codice qui sotto con un modulo personalizzato.)

require.cache è un oggetto le cui chiavi sono percorso del file del modulo, con valori associati che sono oggetti modulo. Ad esempio, supponiamo che alcuni moduli denominati " foo " in C:\node_modules\foo.js :

> require.cache                             // empty cache
{ } 
> require("foo")                            // require foo
{ bar: 'baz' }
> require.cache                             // cache now populated
{ 'C:\node_modules\foo.js':
   { id: 'C: \node_modules\foo.js',
     exports: { bar: 'baz' },
     parent: { ... },
     filename: 'C:\node_modules\foo.js',
     ...
     paths:
      [ ... ] } }

Il valore corrente del modulo foo è in require.cache["C:\node_modules\foo.js"].exports . Possiamo utilizzare require.resolve per ottenere il percorso del file del modulo dal nome, in modo che possiamo esprimerlo anche come require.cache[require.resolve("foo")].exports .

Se chiamiamo require("foo") una seconda volta, Nodo vede che require.cache[require.resolve("foo")] è definito, e quindi restituisce il valore di require.cache[require.resolve("foo")].exports invece di rieseguire il codice di creazione del modulo. Questa proprietà exports del modulo foo in require.cache è la singola istanza del valore di esportazione del modulo foo , restituita con ogni chiamata successiva a require("foo") .

Un'implicazione interessante qui è che puoi delete require.cache[require.resolve("foo")] per forzare un ricaricamento del modulo foo con la prossima chiamata a require("foo") , perché l'oggetto che descrive il modulo viene rimosso dall'oggetto require.cache .

Che cosa significa per me?

Senza require , puoi ancora condividere valori tra moduli usando le variabili globali. Ad esempio, il tuo caso Alpha / Beta / Gamma funzionerebbe altrettanto bene con solo l'impostazione Beta e Gamma e la lettura del valore globale global.a . Invece, con il sistema require del nodo, in realtà stai impostando e leggendo global.require.cache[require.resolve("alpha")].exports.a , il quale nodo ti consente di leggere esattamente come require("alpha").a .

Infatti, se vuoi solo condividere un valore e non hai bisogno di importare i tuoi dati condivisi come modulo, potresti anche usare un oggetto namespacing, cioè avere beta e gamma per impostare e leggere le proprietà dell'oggetto% codice%. Il vantaggio principale dell'utilizzo di global.alpha è che non è necessario impostare require esterno agli altri script, mentre è necessario definire require("alpha") prima di global.alpha = {} ing Beta e Gamma. (In alternativa, potresti definire in modo condizionale require in ogni modulo basato su un controllo global.alpha , per vedere se è il primo modulo ad usarlo.)

    
risposta data 11.06.2013 - 19:23
fonte
3

La condivisione dei dati tra i moduli dipende da come e da quali moduli vengono esportati. È importante tenere presente che require () memorizza nella cache e restituisce la variabile exports . Ad esempio:

// alpha.js 
module.exports.a = 5; // returns 'exports' which is an empty object
                      // with "a" as a property. node caches this object

// gamma.js
var alpha = require("alpha");
alpha.a = 666;  // alpha is a reference to the exports object

// beta.js
var alpha = require("alpha");
console.log(alpha.a); // prints 666

L'aggiornamento (alpha.a = 666) dovrebbe funzionare. Ciò significa che beta.js dovrebbe in effetti ottenere l'ultimo valore ogni volta.

Ma se lo fai:

// alpha.js
module.exports = 5; // returns it as an integer which is cached by node.

// gamma.js
var alpha = require("alpha");
alpha = 666; // overwrites the local copy, but nothing else happens

// beta.js
var alpha = require("alpha");
console.log(alpha); // still prints 5

A proposito, facendo:

// alpha.js
exports = 5;

fallisce perché quel codice è (concettualmente) come questo:

// alpha.js
module.exports = {};
var exports = module.exports;
exports = 5;
return module.exports; // returns {}, not 5
    
risposta data 11.06.2013 - 17:29
fonte

Leggi altre domande sui tag