Apa sebenarnya kegunaan dari WeakMap
struktur data diperkenalkan pada ECMAScript 6?
Karena kunci yang lemah menciptakan peta referensi yang kuat untuk nilai yang sesuai, memastikan bahwa nilai yang telah dimasukkan ke lemah peta akan pernah menghilang selama utamanya adalah masih hidup, hal ini dapat't dapat digunakan untuk memo tabel, cache atau apa pun yang anda biasanya akan menggunakan lemah referensi, peta dengan lemah nilai-nilai, dll. untuk.
Tampaknya bagi saya bahwa ini:
weakmap.set(key, value);
...adalah salah bundaran cara untuk mengatakan ini:
key.value = value;
Apa beton menggunakan kasus-kasus yang saya hilang?
WeakMaps menyediakan cara untuk memperpanjang benda-benda dari luar tanpa mengganggu pengumpulan sampah. Setiap kali anda ingin memperpanjang obyek tetapi dapat't karena disegel - atau dari sumber eksternal - yang WeakMap dapat diterapkan.
Sebuah WeakMap adalah peta (kamus) dimana kunci lemah - bahwa, jika semua referensi untuk key hilang dan tidak ada lagi referensi untuk nilai - value dapat menjadi sampah yang dikumpulkan. Let's acara pertama ini melalui contoh-contoh, kemudian menjelaskan sedikit dan akhirnya selesai dengan penggunaan nyata.
Let's mengatakan saya'm menggunakan API yang memberi saya sebuah objek tertentu:
var obj = getObjectFromLibrary();
Sekarang, saya memiliki sebuah metode yang menggunakan objek:
function useObj(obj){
doSomethingWith(obj);
}
Saya ingin melacak berapa kali metode ini disebut dengan objek tertentu dan melaporkan jika terjadi lebih dari N kali. Naif orang akan berpikir untuk menggunakan Peta:
var map = new Map(); // maps can have object keys
function useObj(obj){
doSomethingWith(obj);
var called = map.get(obj) || 0;
called++; // called one more time
if(called > 10) report(); // Report called more than 10 times
map.set(obj, called);
}
Ini bekerja, tapi memiliki kebocoran memori - kita sekarang dapat melacak setiap satu perpustakaan objek diteruskan ke fungsi yang menjaga perpustakaan benda-benda dari yang pernah menjadi sampah yang dikumpulkan. Alih - kita dapat menggunakan WeakMap
:
var map = new WeakMap(); // create a weak map
function useObj(obj){
doSomethingWith(obj);
var called = map.get(obj) || 0;
called++; // called one more time
if(called > 10) report(); // Report called more than 10 times
map.set(obj, called);
}
Dan kebocoran memori hilang.
Beberapa kasus penggunaan yang dinyatakan akan menyebabkan kebocoran memori dan diaktifkan oleh `WeakMap ini meliputi:
Hal ini dapat digunakan untuk memperpanjang objek dari luar. Let's memberikan praktis (diadaptasi, semacam real - untuk membuat titik) contoh dari dunia nyata Node.js.
Let's mengatakan anda're Node.js dan anda memiliki Janji
benda - sekarang anda ingin melacak semua saat ini menolak janji-janji - namun, anda jangan not ingin menjaga mereka dari menjadi sampah yang dikumpulkan dalam hal tidak ada referensi yang ada untuk mereka.
Sekarang, anda don't ingin menambahkan sifat asli benda-benda untuk alasan yang jelas - sehingga anda're terjebak. Jika anda membuat referensi untuk janji anda're menyebabkan kebocoran memori karena tidak ada pengumpulan sampah dapat terjadi. Jika anda don't menjaga referensi maka anda bisa't menyimpan informasi tambahan tentang individu menjanjikan. Apapun skema yang melibatkan menyimpan ID dari janji berarti anda butuh referensi untuk itu.
WeakMaps berarti bahwa kunci lemah. Tidak ada cara untuk menghitung lemah peta atau untuk mendapatkan semua nilai-nilai. Di lemah peta, anda dapat menyimpan data berdasarkan kunci dan ketika kunci mendapat sampah yang dikumpulkan begitu juga nilai-nilai.
Ini berarti bahwa mengingat janji anda dapat menyimpan state tentang hal itu - dan benda itu masih bisa menjadi sampah yang dikumpulkan. Kemudian, jika anda mendapatkan referensi ke objek anda dapat memeriksa jika anda memiliki salah satu negara yang berkaitan dengan itu dan melaporkannya.
Ini digunakan untuk melaksanakan tidak tertangani penolakan kait oleh Petka Antonov sebagai ini:
process.on('unhandledRejection', function(reason, p) {
console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
// application specific logging, throwing an error, or other logic here
});
Kami menjaga informasi tentang janji-janji dalam peta dan dapat mengetahui ketika ditolak janji ditangani.
Sebuah use case dapat digunakan sebagai kamus untuk pendengar, saya memiliki seorang rekan kerja yang melakukan itu. Hal ini sangat membantu karena setiap pendengar secara langsung ditargetkan dengan cara melakukan hal-hal. Selamat tinggal pendengar.on
.
Tapi dari yang lebih abstrak sudut pandang, WeakMap
ini terutama kuat untuk kemudian lenyap akses ke dasarnya apapun, anda don't perlu namespace untuk mengisolasi anggotanya karena sudah tersirat oleh sifat dari struktur ini. I'm cukup yakin anda bisa melakukan beberapa memori utama perbaikan dengan mengganti awkwards berlebihan objek tombol (meskipun mendekonstruksi apa yang bekerja untuk anda).
Saya sekarang menyadari bahwa saya menekankan ini bukan cara terbaik untuk mengatasi masalah dan sebagai Benjamin Gruenbaum menunjuk keluar (check out-nya menjawab, jika itu's tidak sudah di atas saya :p), masalah ini tidak bisa diselesaikan dengan teratur Peta
, karena itu akan bocor, jadi kekuatan utama WeakMap
adalah bahwa hal itu tidak mengganggu pengumpulan sampah mengingat bahwa mereka tidak menyimpan referensi.
Berikut adalah kode yang sebenarnya dari rekan kerja saya (terima kasih kepada dia untuk berbagi)
Sumber lengkap di sini, it's tentang pendengar manajemen yang saya bicarakan di atas (anda juga bisa lihat di spesifikasi)
var listenableMap = new WeakMap();
export function getListenable (object) {
if (!listenableMap.has(object)) {
listenableMap.set(object, {});
}
return listenableMap.get(object);
}
export function getListeners (object, identifier) {
var listenable = getListenable(object);
listenable[identifier] = listenable[identifier] || [];
return listenable[identifier];
}
export function on (object, identifier, listener) {
var listeners = getListeners(object, identifier);
listeners.push(listener);
}
export function removeListener (object, identifier, listener) {
var listeners = getListeners(object, identifier);
var index = listeners.indexOf(listener);
if(index !== -1) {
listeners.splice(index, 1);
}
}
export function emit (object, identifier, ...args) {
var listeners = getListeners(object, identifier);
for (var listener of listeners) {
listener.apply(object, args);
}
}
WeakMap
bekerja dengan baik untuk enkapsulasi dan menyembunyikan informasi
WeakMap
ini hanya tersedia untuk ES6 dan di atas. A WeakMap
adalah kumpulan kunci dan nilai pasangan mana kunci harus menjadi sebuah objek. Dalam contoh berikut, kita akan membangun sebuah WeakMap
dengan dua item:
var map = new WeakMap();
var pavloHero = {first: "Pavlo", last: "Hero"};
var gabrielFranco = {first: "Gabriel", last: "Franco"};
map.set(pavloHero, "This is Hero");
map.set(gabrielFranco, "This is Franco");
console.log(map.get(pavloHero));//This is Hero
Kami menggunakan set()
metode untuk menentukan hubungan antara objek dan item lain (string dalam kasus kami). Kami menggunakan get()
metode untuk mengambil item yang berhubungan dengan suatu objek. Aspek yang menarik dari WeakMap ini adalah fakta bahwa ia memegang lemah referensi untuk kunci di dalam peta. Lemah referensi berarti bahwa jika objek dihancurkan, garbage collector akan menghapus seluruh entri dari
WeakMap`, dengan demikian membebaskan memori.
var TheatreSeats = (function() {
var priv = new WeakMap();
var _ = function(instance) {
return priv.get(instance);
};
return (function() {
function TheatreSeatsConstructor() {
var privateMembers = {
seats: []
};
priv.set(this, privateMembers);
this.maxSize = 10;
}
TheatreSeatsConstructor.prototype.placePerson = function(person) {
_(this).seats.push(person);
};
TheatreSeatsConstructor.prototype.countOccupiedSeats = function() {
return _(this).seats.length;
};
TheatreSeatsConstructor.prototype.isSoldOut = function() {
return _(this).seats.length >= this.maxSize;
};
TheatreSeatsConstructor.prototype.countFreeSeats = function() {
return this.maxSize - _(this).seats.length;
};
return TheatreSeatsConstructor;
}());
})()
Saya menggunakan WeakMap
untuk cache khawatir-gratis memoization fungsi yang bagus di abadi objek sebagai parameter.
Memoization adalah cara mewah untuk mengatakan "setelah anda menghitung nilai, cache sehingga anda don't harus menghitung lagi".
Berikut ini's contoh:
// using immutable.js from here https://facebook.github.io/immutable-js/
const memo = new WeakMap();
let myObj = Immutable.Map({a: 5, b: 6});
function someLongComputeFunction (someImmutableObj) {
// if we saved the value, then return it
if (memo.has(someImmutableObj)) {
console.log('used memo!');
return memo.get(someImmutableObj);
}
// else compute, set, and return
const computedValue = someImmutableObj.get('a') + someImmutableObj.get('b');
memo.set(someImmutableObj, computedValue);
console.log('computed value');
return computedValue;
}
someLongComputeFunction(myObj);
someLongComputeFunction(myObj);
someLongComputeFunction(myObj);
// reassign
myObj = Immutable.Map({a: 7, b: 8});
someLongComputeFunction(myObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
Beberapa hal yang perlu diperhatikan:
Lemah Peta dapat digunakan untuk menyimpan metadata tentang elemen DOM tanpa mengganggu pengumpulan sampah atau membuat rekan kerja gila pada kode anda. Misalnya, anda bisa menggunakannya untuk indeks numerik semua elemen dalam sebuah halaman web.
var elements = document.getElementsByTagName('*'),
i = -1, len = elements.length;
while (++i !== len) {
// Production code written this poorly makes me want to cry:
elements[i].lookupindex = i;
elements[i].elementref = [];
elements[i].elementref.push( elements[Math.pow(i, 2) % len] );
}
// Then, you can access the lookupindex's
// For those of you new to javascirpt, I hope the comments below help explain
// how the ternary operator (?:) works like an inline if-statement
document.write(document.body.lookupindex + '<br />' + (
(document.body.elementref.indexOf(document.currentScript) !== -1)
? // if(document.body.elementref.indexOf(document.currentScript) !== -1){
"true"
: // } else {
"false"
) // }
);
var DOMref = new WeakMap(),
__DOMref_value = Array,
__DOMref_lookupindex = 0,
__DOMref_otherelement = 1,
elements = document.getElementsByTagName('*'),
i = -1, len = elements.length, cur;
while (++i !== len) {
// Production code written this greatly makes me want to 😊:
cur = DOMref.get(elements[i]);
if (cur === undefined)
DOMref.set(elements[i], cur = new __DOMref_value)
cur[__DOMref_lookupindex] = i;
cur[__DOMref_otherelement] = new WeakSet();
cur[__DOMref_otherelement].add( elements[Math.pow(i, 2) % len] );
}
// Then, you can access the lookupindex's
cur = DOMref.get(document.body)
document.write(cur[__DOMref_lookupindex] + '<br />' + (
cur[__DOMref_otherelement].has(document.currentScript)
? // if(cur[__DOMref_otherelement].has(document.currentScript)){
"true"
: // } else {
"false"
) // }
);
Perbedaannya mungkin terlihat diabaikan, selain dari fakta bahwa weakmap versi yang lebih lama, namun ada perbedaan besar antara dua potongan kode yang ditunjukkan di atas. Pertama, cuplikan kode, tanpa lemah maps, potongan kode toko referensi setiap cara yang antara elemen DOM. Hal ini untuk mencegah elemen DOM dari sampah yang dikumpulkan. Matematika.pow(i, 2) % len]
mungkin tampak seperti sebuah eksentrik itu tidak akan ada gunanya, tapi berpikir lagi: banyak kode produksi telah DOM referensi yang memantul di seluruh dokumen. Sekarang, untuk kedua potongan kode, karena semua referensi ke elemen-elemen yang lemah, ketika anda menghapus sebuah node, browser ini dapat menentukan bahwa node tidak digunakan (tidak dapat dicapai dengan kode anda), dan dengan demikian menghapusnya dari memori. Alasan mengapa anda harus peduli tentang penggunaan memori, dan memori jangkar (hal-hal seperti dulu cuplikan kode yang mana yang tidak terpakai unsur-unsur yang diadakan di memori) adalah karena lebih banyak penggunaan memori yang lebih berarti browser GC-upaya (untuk mencoba untuk membebaskan memori untuk mencegah browser crash) berarti lebih lambat pengalaman browsing dan kadang-kadang browser crash.
Adapun polyfill ini, saya akan merekomendasikan saya sendiri perpustakaan (ditemukan di sini @ github). Hal ini sangat ringan perpustakaan yang hanya akan polyfill itu tanpa ada cara-terlalu kompleks kerangka kerja yang anda mungkin menemukan di lain polyfills.
~ Happy coding!