Apakah mungkin untuk membuat "referensi lemah" di javascript?

98

Apakah ada cara dalam javascript untuk membuat "referensi lemah" ke objek lain? Berikut adalah halaman wiki yang menjelaskan apa itu referensi yang lemah. Berikut adalah artikel lain yang menjelaskannya di Java. Adakah yang bisa memikirkan cara untuk menerapkan perilaku ini di javascript?

Stephen Cagle
sumber
4
Referensi yang lemah sedang dibahas untuk ES6. Jaga agar mata Anda tetap terbuka.
Ryan Smith
2
* Wiki / diskusi spesifikasi resmi di wiki.ecmascript.org/doku.php?id=strawman:weak_refs , saat ini “Terakhir diubah: 2013/02/02 22:25” * beberapa diskusi spesifikasi lainnya di esdiscuss.org/topic/what -is-the-status-of-weak-reference , postingan terakhir saat ini "Sun 3 Mar 11:56:05 PST 2013"
Destiny Architect
Dalam kebanyakan kasus, WR adalah upaya untuk memecahkan Masalah Pendengar yang Lapsed , dibahas di sini: [ stackoverflow.com/questions/43758217/… . Jika pertanyaan itu memiliki jawaban yang bagus, saya kira tidak akan ada banyak kebutuhan untuk WR.
Yakobus
@supercat Saya telah memposting jawaban untuk pertanyaan pendengar yang sudah tidak berlaku .
Yakobus

Jawaban:

39

Tidak ada dukungan bahasa untuk weakrefs di JavaScript. Anda dapat menggulung sendiri menggunakan penghitungan referensi manual, tetapi tidak terlalu mulus. Anda tidak dapat membuat objek pembungkus proxy, karena dalam objek JavaScript tidak pernah tahu kapan objek tersebut akan dikumpulkan sampahnya.

Jadi 'referensi lemah' Anda menjadi kunci (mis. Bilangan bulat) dalam pencarian sederhana, dengan metode add-reference dan remove-reference, dan bila tidak ada referensi yang dilacak secara manual lagi, maka entri dapat dihapus, membiarkan pencarian selanjutnya pada kunci itu untuk mengembalikan null.

Ini sebenarnya bukan ref yang lemah, tetapi bisa menyelesaikan beberapa masalah yang sama. Ini biasanya dilakukan dalam aplikasi web yang kompleks untuk mencegah kebocoran memori dari browser (biasanya IE, terutama versi yang lebih lama) ketika ada loop referensi antara Node DOM atau pengendali kejadian, dan objek yang terkait dengannya seperti penutupan. Dalam kasus ini, skema penghitungan referensi penuh bahkan mungkin tidak diperlukan.

bobince
sumber
2
Saya belum memeriksa (atau menggunakan) kode dengan cermat, tetapi es-lab memiliki skrip yang menyediakan emulasi WeakMap dasar . Aurora 6 (Mozilla) memiliki implementasi WeakMap non-standar .
theazureshadow
2
Dengan ES6 jawaban ini tidak lagi benar. Lihat jawaban saya di bawah stackoverflow.com/a/28567560/745190
thelastshadow
9
Itu masih benar, karena ES6 WeakMaps bukanlah referensi lemah yang sebenarnya. WeakMaps menerima objek sebagai kunci saja, dan referensi ke objek ini dipegang dengan lemah. Lihat stackoverflow.com/questions/32397729/…
CodeManX
Saya menulis kelas untuk meniru peta yang lemah dan mempostingnya di sini: stackoverflow.com/a/47017206/491553
Ryan Shillington
11

Pembaruan: September 2019

Referensi yang lemah belum dapat digunakan, tetapi kemungkinan besar akan segera dapat dilakukan, karena WeakRef di JavaScript sedang dalam proses. Detail di bawah.

Usul

Proposal saat ini dalam Tahap 3 yang berarti memiliki spesifikasi yang lengkap dan penyempurnaan lebih lanjut akan membutuhkan umpan balik dari implementasi dan pengguna.

The weakref usulan meliputi dua potong baru utama dari fungsi:

  • Membuat referensi lemah ke objek dengan kelas WeakRef
  • Menjalankan finalizer yang ditentukan pengguna setelah objek dikumpulkan dari sampah, dengan kelas FinalizationGroup

Kasus penggunaan

Sebuah penggunaan utama untuk referensi lemah adalah untuk menerapkan cache atau pemetaan memegang benda besar, di mana itu yang diinginkan bahwa sebuah objek besar tidak tetap hidup semata-mata karena muncul dalam cache atau pemetaan.

Finalisasi adalah eksekusi kode untuk membersihkan setelah objek menjadi tidak terjangkau untuk eksekusi program. Finalizer yang ditentukan pengguna mengaktifkan beberapa kasus penggunaan baru, dan dapat membantu mencegah kebocoran memori saat mengelola resource yang tidak diketahui oleh pengumpul sampah.

Sumber dan bacaan lebih lanjut

https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references

M. Twarog
sumber
1
Firefox Nightly telah menambahkan dukungan eksperimental untuk WeakRef. Berikut adalah contoh implementasi yang menggunakannya untuk membuat versi WeakSet yang dapat diulang: gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley
3

Referensi benar-benar lemah, tidak, belum (tapi pembuat browser melihat subjeknya). Tapi di sini ada ide tentang bagaimana mensimulasikan referensi yang lemah.

Anda dapat membuat cache yang digunakan untuk mengarahkan objek Anda. Saat sebuah objek disimpan, cache menyimpan prediksi berapa banyak memori yang akan digunakan objek tersebut. Untuk beberapa item, seperti menyimpan gambar, ini langsung berhasil. Bagi orang lain ini akan lebih sulit.

Saat Anda membutuhkan sebuah objek, Anda kemudian meminta cache untuk itu. Jika cache memiliki objek, itu dikembalikan. Jika tidak ada, maka item dibuat, disimpan, dan kemudian dikembalikan.

Referensi yang lemah disimulasikan oleh item penghapus cache, ketika jumlah total memori yang diprediksi mencapai tingkat tertentu. Ini akan memprediksi item mana yang paling sedikit digunakan berdasarkan seberapa sering mereka diambil, tertimbang dengan berapa lama mereka dibawa keluar. Biaya 'kalkulasi' juga dapat ditambahkan, jika kode yang membuat item tersebut dimasukkan ke cache sebagai penutup. Ini akan memungkinkan cache menyimpan item yang sangat mahal untuk dibuat atau dibuat.

Algoritme penghapusan adalah kuncinya, karena jika Anda melakukan kesalahan ini maka Anda bisa menghapus item yang paling populer. Ini akan menyebabkan kinerja yang buruk.

Selama cache adalah satu-satunya objek dengan referensi permanen ke objek yang disimpan, maka sistem di atas akan bekerja dengan baik sebagai alternatif referensi lemah yang sebenarnya.

JL235
sumber
25
Bukankah sebagian besar dari apa yang Anda katakan tidak relevan dengan weakrefs?
Erik Kaplun
22
@ JL235 - penggunaan penting untuk referensi yang lemah bukan untuk cache tetapi untuk penangan kejadian. Saya memiliki beberapa objek yang, meskipun ada, harus mengamati beberapa peristiwa lain - tetapi saya tidak ingin fakta bahwa itu ada dalam daftar pemberitahuan untuk dijadikan referensi untuk tujuan GC.
Malvolio
7
Referensi yang lemah tidak ada hubungannya dengan caching. Referensi yang lemah berarti Anda ingin melacak sesuatu, tetapi jika tidak ada referensi yang tersisa ke objek yang dilacak, Anda mengizinkannya untuk dihapus.
fabspro
8
Jelas ada kasus penggunaan untuk membuat cache menggunakan referensi yang lemah untuk kedaluwarsa otomatis.
Phil Freeman
5
Caching secara tradisional merupakan alasan utama untuk referensi yang lemah. Event handler DOM hanyalah beberapa hal kereta IE explorer.
axkibe
2

Menggunakan mekanisme caching untuk meniru referensi yang lemah, seperti yang disarankan JL235 di atas , adalah hal yang wajar. Jika referensi yang lemah akan ada secara asli, Anda akan mengamati perilaku seperti ini:

this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not

Sedangkan dengan cache Anda akan mengamati:

this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts

Sebagai pemegang referensi, Anda tidak boleh membuat asumsi apa pun tentang kapan itu merujuk ke suatu nilai, ini tidak berbeda dengan menggunakan cache

Markus
sumber
-4

EcmaScript 6 (ES Harmony) memiliki objek WeakMap . Dukungan browser di antara browser modern cukup bagus (3 versi terakhir Firefox, chrome dan bahkan versi IE yang akan datang mendukungnya).

bayangan terakhir
sumber
29
Ini tidak persis sama. A WeakMaptidak memberikan referensi lemah ke objek-- bukan nilai yang menjadi referensi lemah di WeakMap, tetapi kuncinya . Fakta bahwa referensi yang lemah ada di peta hanyalah mekanisme pencegahan kebocoran memori, dan sebaliknya tidak dapat diamati oleh pengguna.
EyasSH
1
Anda benar bahwa kuncinya yang lemah, bukan nilainya. Tetapi seluruh tujuan penggunaan referensi yang lemah adalah untuk memungkinkan pengumpulan sampah dari objek yang direferensikan. OP memposting dua tautan, yang kedua adalah tentang menambahkan id ke objek yang tidak dapat Anda perluas, dan sebenarnya itu merekomendasikan menggunakan WeakHashMap, Java yang setara dengan WeakMap JavaScript.
theelastshadow
12
semoga berhasil menggunakan WeakMap untuk mengimplementasikan referensi yang lemah karena weakmap.get(new String('any possible key that has ever existed or ever will exist'))akan selalu demikian undefined. Tidak berguna. Tidak memilih!
user3338098
-5

http://www.jibbering.com/faq/faq_notes/closures.html

ECMAScript menggunakan pengumpulan sampah otomatis. Spesifikasi tidak menentukan detailnya, menyerahkannya kepada pelaksana untuk memilahnya, dan beberapa implementasi diketahui memberikan prioritas yang sangat rendah pada operasi pengumpulan sampahnya. Tetapi gagasan umumnya adalah bahwa jika sebuah objek menjadi tidak dapat dirujuk (dengan tidak memiliki referensi yang tersisa untuk itu dibiarkan dapat diakses untuk mengeksekusi kode) itu menjadi tersedia untuk pengumpulan sampah dan pada suatu saat akan dimusnahkan dan sumber daya apa pun yang dikonsumsinya dibebaskan dan dikembalikan ke sistem untuk digunakan kembali.

Ini biasanya akan menjadi kasus saat keluar dari konteks eksekusi. Struktur rantai cakupan, objek Aktivasi / Variabel, dan objek apa pun yang dibuat dalam konteks eksekusi, termasuk objek fungsi, tidak lagi dapat diakses dan akan tersedia untuk pengumpulan sampah.

Artinya tidak ada satu-satunya yang lemah yang tidak lagi tersedia.

branchgabriel.dll
sumber
10
Menghindari siklus referensi bukanlah satu-satunya alasan untuk menggunakan referensi yang lemah. Mereka sangat berguna untuk objek contoh penggabungan / caching dan sebagainya.
lembut
Definisi dari WeakReference bukanlah pertanyaan. Juga setuju dengan komentar di atas.
Yuri Yaryshev