Saya baru-baru ini menemukan artikel ini tentang cara menulis singleton di Node.js. Saya tahu dokumentasi require
menyatakan bahwa:
Modul di-cache setelah pertama kali dimuat. Beberapa panggilan ke
require('foo')
mungkin tidak menyebabkan kode modul dijalankan berkali-kali.
Jadi tampaknya setiap modul yang diperlukan dapat dengan mudah digunakan sebagai singleton tanpa kode boilerplate tunggal.
Pertanyaan:
Apakah artikel di atas memberikan penjelasan tentang solusi untuk membuat singleton?
javascript
node.js
design-patterns
singleton
mkoryak
sumber
sumber
Jawaban:
Ini pada dasarnya berkaitan dengan cache nodejs. Polos dan sederhana.
https://nodejs.org/api/modules.html#modules_caching
(v 6.3.1)
Jadi secara sederhana.
Jika Anda menginginkan Singleton; ekspor sebuah objek .
Jika Anda tidak menginginkan Singleton; ekspor fungsi (dan lakukan barang / kembalikan barang / apa pun di fungsi itu).
Agar SANGAT jelas, jika Anda melakukan ini dengan benar, seharusnya berfungsi, lihat https://stackoverflow.com/a/33746703/1137669 (jawaban Allen Luce). Ini menjelaskan dalam kode apa yang terjadi ketika caching gagal karena nama file yang diselesaikan secara berbeda. Tetapi jika Anda SELALU menyelesaikan dengan nama file yang sama, seharusnya berfungsi.
Perbarui 2016
membuat singleton yang sebenarnya di node.js dengan simbol es6 Solusi lain : di tautan ini
Perbarui 2020
Jawaban ini mengacu pada CommonJS (cara Node.js sendiri untuk mengimpor / mengekspor modul). Node.js kemungkinan besar akan beralih ke Modul ECMAScript : https://nodejs.org/api/esm.html (ECMAScript adalah nama asli JavaScript jika Anda tidak tahu)
Saat bermigrasi ke ECMAScript, baca berikut ini untuk saat ini: https://nodejs.org/api/esm.html#esm_writing_dual_packages_ sementara_avoiding_or_minimizing_hazards
sumber
Semua hal di atas terlalu rumit. Ada aliran pemikiran yang mengatakan pola desain menunjukkan kekurangan bahasa yang sebenarnya.
Bahasa dengan OOP berbasis prototipe (tanpa kelas) sama sekali tidak membutuhkan pola tunggal. Anda cukup membuat satu (ton) objek dengan cepat dan kemudian menggunakannya.
Adapun modul dalam node, ya, secara default mereka di-cache, tetapi dapat di-tweak misalnya jika Anda ingin hot-loading perubahan modul.
Tapi ya, jika Anda ingin menggunakan objek bersama secara keseluruhan, memasukkannya ke dalam modul ekspor tidak masalah. Hanya saja, jangan memperumitnya dengan "pola tunggal", tidak perlu di JavaScript.
sumber
There is a school of thought which says design patterns are showing deficiencies of actual language.
Tidak. Saat cache modul Node gagal, pola tunggal itu gagal. Saya memodifikasi contoh untuk berjalan dengan penuh makna di OSX:
Ini memberikan keluaran yang diantisipasi oleh penulis:
Tetapi modifikasi kecil mengalahkan caching. Di OSX, lakukan ini:
Atau, di Linux:
Kemudian ubah
sg2
baris yang diminta menjadi:Dan bam , singleton dikalahkan:
Saya tidak tahu cara yang dapat diterima untuk menyiasati ini. Jika Anda benar-benar merasa perlu untuk membuat sesuatu seperti tunggal dan tidak keberatan mencemari namespace global (dan banyak masalah yang dapat terjadi), Anda dapat mengubah penulis
getInstance()
danexports
baris menjadi:Meski begitu, saya tidak pernah mengalami situasi di sistem produksi di mana saya perlu melakukan hal seperti ini. Saya juga tidak pernah merasa perlu menggunakan pola tunggal di Javascript.
sumber
Melihat sedikit lebih jauh di Modul Caching Peringatan di modul docs:
Jadi, tergantung di mana Anda berada saat membutuhkan modul, dimungkinkan untuk mendapatkan contoh modul yang berbeda.
Sepertinya modul bukanlah solusi sederhana untuk menciptakan lajang.
Edit: Atau mungkin mereka adalah . Seperti @mkoryak, saya tidak dapat menemukan kasus di mana satu file dapat diselesaikan ke nama file yang berbeda (tanpa menggunakan symlink). Tetapi (seperti komentar @JohnnyHK), beberapa salinan file di
node_modules
direktori yang berbeda akan dimuat dan disimpan secara terpisah.sumber
node_modules
mana masing-masing bergantung pada modul yang sama, tetapi ada salinan terpisah dari modul dependen itu di bawahnode_modules
subdirektori dari masing-masing dari dua modul yang berbeda.require('./db')
dalam dua file terpisah, kode untukdb
modul dijalankan dua kalirequire('../lib/myModule.js');
dalam satu file dan filerequire('../lib/mymodule.js');
lain dan tidak mengirimkan objek yang sama.Singleton di node.js (atau di browser JS, dalam hal ini) seperti itu sama sekali tidak diperlukan.
Karena modul di-cache dan stateful, contoh yang diberikan pada tautan yang Anda berikan dapat dengan mudah ditulis ulang dengan lebih sederhana:
sumber
may not
berlaku ketika Andanpm link
modul lain selama pengembangan. Jadi berhati-hatilah saat menggunakan modul yang mengandalkan satu instance seperti eventBus.Satu-satunya jawaban di sini yang menggunakan kelas ES6
membutuhkan singleton ini dengan:
Satu-satunya masalah di sini adalah Anda tidak dapat meneruskan params ke konstruktor kelas tetapi itu dapat dielakkan dengan memanggil
init
metode secara manual .sumber
summary
di kelas lain, tanpa menginisialisasi lagi?Anda tidak memerlukan sesuatu yang khusus untuk melakukan singleton di js, kode dalam artikel tersebut bisa jadi:
Di luar node.js (misalnya, di browser js), Anda perlu menambahkan fungsi pembungkus secara manual (ini dilakukan secara otomatis di node.js):
sumber
Lajang baik-baik saja di JS, mereka tidak perlu terlalu bertele-tele.
Dalam node jika Anda memerlukan singleton, misalnya untuk menggunakan instance ORM / DB yang sama di berbagai file di lapisan server Anda, Anda dapat memasukkan referensi ke dalam variabel global.
Cukup tulis modul yang membuat var global jika tidak ada, lalu kembalikan referensi ke sana.
@ allen-luce benar dengan contoh kode catatan kaki yang disalin di sini:
tetapi penting untuk dicatat bahwa penggunaan
new
kata kunci tidak diperlukan. Objek lama, fungsi, iife, dll. Akan berfungsi - tidak ada voodoo OOP yang terjadi di sini.poin bonus jika Anda menutup beberapa obj di dalam fungsi yang mengembalikan referensi ke sana, dan membuat fungsi itu menjadi global - bahkan penugasan ulang variabel global tidak akan mengganggu instance yang sudah dibuat darinya - meskipun ini berguna untuk dipertanyakan.
sumber
module.exports = new Foo()
karena module.exports tidak akan dijalankan lagi, kecuali Anda melakukan sesuatu yang sangat bodohMenjaga agar tetap sederhana.
foo.js
Lalu baru saja
sumber