Node.js modüllerini anlama: birden çok, aynı nesneyi döndürmeyi gerektirir mi?


106

Modül önbelleğe alma ile ilgili node.js dokümantasyonuyla ilgili bir sorum var :

Modüller ilk yüklendikten sonra önbelleğe alınır. Bu, (diğer şeylerin yanı sıra), her gereksinim çağrısının ('foo') , aynı dosyaya çözümlenmesi halinde, döndürülen nesnenin tam olarak aynısını alacağı anlamına gelir.

Zorunlu kılmak için birden çok çağrı ('foo') , modül kodunun birden çok kez çalıştırılmasına neden olmayabilir . Bu önemli bir özelliktir. Bununla birlikte, "kısmen tamamlanmış" nesneler döndürülebilir, böylece geçişli bağımlılıkların döngülere neden olsalar bile yüklenmesine izin verilir.

Ne demek oluyor may?

Gerekirse her zaman aynı nesneyi döndüreceğini bilmek istiyorum . Yani durumda bir modül gerektiren A içinde app.jsve içinde ihracat nesneyi değiştirmek app.js(döner gerektiren bir) ve bundan sonra bir modül gerektiren B içinde app.jskendisi modülü gerektirdiğini A , ben olacak hep o nesnenin değiştirilmiş bir sürümünü veya yeni olsun bir?

// app.js

var a = require('./a');
a.b = 2;
console.log(a.b); //2

var b = require('./b');
console.log(b.b); //2

// a.js

exports.a = 1;

// b.js

module.exports = require('./a');

7
Belgelerdeki bu cümle daha iyi yazılabilirdi. Bana öyle geliyor ki , izin verilmeyen ile aynı olmayabilir , yani, gerekli olan ('foo') çoklu çağrı modül kodunun birden çok kez çalıştırılmasına neden olamaz .
Lucio Paiva

@LucioPaiva Düzeltmek için bir PR oluşturdu: github.com/nodejs/node/pull/23143
mikemaccana

"Hayır, Timmy, daha fazla çikolatanız olmayabilir" ile aynı anlamda [neden olamaz] yerine [neden olamaz] anlamına geliyordu. Yani bu bağlamda, muğlak yazılmış olduğuna katılıyorum.
Ciabaros

Yanıtlar:


76

Her iki takdirde app.jsve b.js, İkamet aynı projede (ve aynı dizinde) daha sonra her ikisi de alacak aynı örneği arasında A. Gönderen node.js belgeler :

... her çağrı require('foo')alacak aynı nesne tam o çözmek olsaydı, dönen aynı dosyaya .


Durum olduğunda farklıdır a.js, b.jsve app.jsvardır farklı npm modüllerin . Örneğin:

[APP] --> [A], [B]
[B]   --> [A]

Bu durumda require('a')içinde app.jsfarklı bir kopyasına çözümlenebileceğini a.jsdaha require('a')içinde b.jsve bu nedenle iade farklı örneğini ait A. Bu davranışı daha ayrıntılı olarak açıklayan bir blog yazısı var .


1
"ve aynı dizinde". [B], [Uygulama] 'nın yaşadığı yerin bir alt klasöründeyken aynı örneği aldım.
Bill Tarbell

1
@BillTarbell Aynı örneği farklı klasörlerden almak istediğimde iki farklı dosya aldım.
MustSeeMelons

1
npm A, B ve APP'yi düz bir dizin yapısına yükleyeceği için bu son uyarı hala geçerli mi? Değilse, bir modül, sonuçlarını diğer birçok modül arasında önbelleğe alacak şekilde nasıl kurulabilir?
Michael

Node.js belgelerinden: "Modüller, çözülen dosya adlarına göre önbelleğe alınır. Modüller, çağıran modülün konumuna bağlı olarak farklı bir dosya adına çözümlenebileceğinden (node_modules klasörlerinden yükleme), ('foo '), farklı dosyalara çözümlenecekse, her zaman tam olarak aynı nesneyi döndürür. " Yapabilecekleriniz Yani değil kullanmak tekil davranış, vaka duyarsız dosya sistemleri veya sembolik bağlantıları ve uygulamak için önbelleği gerektiren aynı modül birden çok kez yüklenmesine neden olabilir böyle. Global verilere ihtiyacınız varsa, "global" nesneyi kullanmanız gerekir.
Tannin

6

node.js, bazı büyük sunucu projelerini yürütürken düğümün 1000 kez dosyaları okumasını engelleyen bir tür önbelleğe alma uygulamasına sahiptir.

Bu önbellek, require.cachenesnede listelenir . Bu nesnenin okunabilir / yazılabilir olduğuna dikkat etmeliyim, bu da işlemi durdurmadan dosyaları önbellekten silme yeteneği verir.

http://nodejs.org/docs/latest/api/globals.html#require.cache

Ouh, soruyu cevaplamayı unuttum. Dışa aktarılan nesnenin değiştirilmesi, bir sonraki modül yüklemesini etkilemez. Bu çok fazla soruna neden olur ... Her zaman nesnenin yeni bir örneğini döndürmeyi gerektir, referans yok. Dosyayı düzenlemek ve önbelleği silmek dışa aktarılan nesneyi değiştirir

Bazı testler yaptıktan sonra node.js, module.exports'u önbelleğe alır. Değişiklik require.cache[{module}].exports, yeni, değiştirilmiş bir döndürülmüş nesne ile sonuçlanır.


1
Gönderdiğim kod gerçekten çalışıyor. b.bdeğeri ile tanımlanır 2. Yani bu örnekte aynı nesne.
Xomby

Bu bir özellik ve bence oldukça kullanışlı. Soru, buna güvenip güvenemeyeceğim. Belgeler, mayhangisinin belirsiz olduğunu söylüyor .
Xomby

A.js'de bir işlevin gereksinim üzerine çalıştırılması hiçbir şeyi değiştirmez ... Döndürülen nesneyi önbelleğe almaya devam eder. Tuhaf, uygulamalarım nasıl çalışıyor? Bunun tek yolu, belgelerde açıklandığı gibi, gerekli olduktan sonra geçirilen bir işlevi yürütmektir.
moe

1
bazen nesneler aynıdır. Buna güvenmeyin, gerekirse tek bir modül örneğini geçirin.
Ricardo Tomasi

Bir gereksinim üzerine yepyeni bir nesneyi geri almanın bir yolu var mı (önbelleğe alınan nesne değil)?
Matt

3

Sorunun gönderilmesinden bu yana belge , başlangıçta "olabilir" in neden kullanıldığını netleştirmek için güncellendi. Şimdi her şeyi açıklığa kavuşturarak sorunun kendisini yanıtlıyor (neyin değiştiğini göstermeye vurgu yapıyorum):

Modüller, ilk yüklendikten sonra önbelleğe alınır. Bu, (diğer şeylerin yanı sıra), her gereksinim çağrısının ('foo'), aynı dosyaya çözümlenmesi halinde, döndürülen nesnenin tam olarak aynısını alacağı anlamına gelir.

Sağlanan require.cache değiştirilmez, çoklu aramalar ( 'foo') gerektirecek olacak modül kod birden çok kez yürütülecek neden olmaz. Bu önemli bir özelliktir. Bununla birlikte, "kısmen tamamlanmış" nesneler döndürülebilir, böylece geçişli bağımlılıkların döngülere neden olsalar bile yüklenmesine izin verilir.


2

Gördüğüm kadarıyla, eğer modül adı önceden yüklenmiş bir dosyaya dönüşürse, önbelleğe alınan modül iade edilecek, aksi takdirde yeni dosya ayrı olarak yüklenecektir.

Yani, önbelleğe alma, çözülen gerçek dosya adına dayanır. Bunun nedeni, genel olarak, dosya hiyerarşisinin farklı seviyelerinde kurulu olan ve buna göre yüklenmesi gereken aynı paketin farklı sürümlerinin olabilmesidir.

Emin olmadığım şey, programcının kontrolü veya farkındalığı altında olmayan önbellek geçersiz kılma vakalarının olup olmadığıdır, bu durum aynı paket dosyasını birden çok kez yanlışlıkla yeniden yüklemeyi mümkün kılabilir.


1

Her seferinde require(x)yeni bir nesne döndürmek istemenizin nedeni , yalnızca o nesneyi doğrudan değiştirdiğiniz içindir - ki bu karşılaştığım bir durumdur - sadece klonlayın ve yalnızca klonu değiştirin ve kullanın, örneğin:

var a = require('./a');
a = JSON.parse(JSON.stringify(a));

0

drex'i deneyin : https://github.com/yuryb/drex

drex güncellemeler için bir modül izliyor ve güncellemeden sonra modülü temiz bir şekilde yeniden gerektiriyor. Yeni kod, sanki yeni kod tamamen farklı bir modül gibi gereklidir () d, bu nedenle require.cache bir sorun değildir.


2
Soru başka bir soruydu, ancak drex geliştirme işleri için gerçekten harika görünüyor. Teşekkürler!
Alex Ivasyuv

0

Bir nesneye ihtiyaç duyduğunuzda, referans adresini talep edersiniz ve nesneyi iki kez isteyerek aynı adresi alırsınız! Aynı nesnenin kopyalarına sahip olmak için onu kopyalamanız (klonlamanız) gerekir.

var obj = require('./obj');

a = JSON.parse(JSON.stringify(obj));
b = JSON.parse(JSON.stringify(obj));
c = JSON.parse(JSON.stringify(obj));

Klonlama birden çok yöntemle yapılır görebilirsiniz Bu daha fazla bilgi için,.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.