'The shadow DOM and encapsulation of JS/CSS and memory consumption
I tried to ask this question earlier tonight but deleted the question because I wasn't doing a good job of it. I learned a bit more through experimenting further to ask what I hope better explains it. I'm asking this question because I want to understand how memory is consumed and released when repeatedly fetching new resources to a shadow-DOM element relative to using an iframe.
I'm having some trouble understanding what is really taking place in the shadow DOM regarding scripts. From reading CSS Tricks article on templates and the shadow DOM and the MDN document on Using the Shadow DOM, and experimenting with this, it appears that the CSS is encapsulated sort of automatically. I cannot tell if the CSS styles are removed from memory when the node containing the shadow element is removed from the DOM. Perhaps all that takes place there is similar to placing shadowRoot at the front of every CSS selector, such that the styles remain in memory after the shadowRoot is removed or content replaced.
The JS doesn't appear to be encapsulated in the sense that it exists only in a module for a particular segment of the DOM. I'm just a hack and don't know much about classes but it appears that all that is done is the references upon which the JS functions operate are selected from the shadowRoot rather than the document level; and if the shadow root was removed from the document the script would still be in memory. If the script is included in a template element, once the template is imported and appended, the script references apply to the document. But through the examples using a class structure, the references are changed to the shadowRoot. We could do that without a shadow DOM and just execute shadow_element.querySelectorAll() rather than document.querySelectorAll(). Could we not?
In other words, it appears that the script is on the window element but acts upon a subset of the DOM identified by the shadowRoot, such that if the shadowRoot element is removed, the script remains. Thus, although it is claimed that the shadow DOM encapsulates CSS and JS like an iframe, if the content in the shadowRoot is changed several times via fetching new resources, will the CSS and JS "grow" in memory rather than being garbage collected such as when the contents of an iframe are replaced?
If instead the script was set up based on "this" and invoked through a function.call(this), would it result in the script being cleared from memory when the shadowRoot is deleted?
tabs[i] = new tab(...) {}
tabs[i].shadow = DOM_element.attachShadow({mode: 'open'});
/* fetch the HTML, CSS, JS from the server. */
/* all references in JS are to this.shadow. */
/* such as:
function init() {
console.log("shadow script");
this.shadow.querySelectorAll("DIV").forEach( v => v.addEventListener( "mousedown", (evt) => {
evt.stopPropagation();
let e = evt.target;
if ( e.matches( "p") ) {
e.classList.toggle("plain");
}
}, false ));
this.log = function(msg) { console.log(msg); };
};
tabs[i].shadow.appendChild(styles);
tabs[i].shadow.appendChild(html);
tabs[i].shadow.appendChild(script);
init.call(tabs[i]);
tabs[i].log("Successfully injected script.");
delete tabs[i];
The following snippet applies the script in this manner and it appears to work the same as when through a class. Just click on the light and shadow paragraphs. I realize that the class structure is used to make a new custom element but that's not my objective. I just want to repeatedly fetch new resources that have some specific styling and some specific interaction. I think the common styling can be achieved through a link and caching the style sheet of common styles.
All the snippet shows is that the light and shadow DOM have separate styles and run separate JS. It uses the object method described above. If don't use the object then still have to use the shadowRoot rather than document with querySelectorAll. Appending the script to the shadowRoot, such as if fetched a generic document, won't automatically apply reference to the shadowRoot only as appears to take place for CSS.
sc.textContent = `function init() { console.log("shadow script");
tab.sh.querySelectorAll("DIV").forEach( v => v.addEventListener( "mousedown", (evt) => {
evt.stopPropagation();
console.log( "shadow" );
let e = evt.target;
if ( e.matches( "p") ) {
e.classList.toggle("plain");
}
}, false ));
this.log = function(msg) { console.log(msg); };
}`;
var d_light = document.querySelectorAll(".light");
d_light.forEach( v => v.addEventListener( "mousedown", (evt) => {
evt.stopPropagation(); //console.log("light");
let e = evt.target;
if ( e.matches( "p") ) {
e.classList.toggle("plain");
}
}, false )
);
var tab = new Object();
var el_t1 = document.importNode(document.getElementById('t1').content, true)
var el_sh = document.querySelector("div.shadow");
tab.sh = el_sh.attachShadow({mode: 'open'});
var st = document.createElement("STYLE");
var sc = document.createElement("SCRIPT");
st.textContent = `p {
background-color: rgb(73,110,147);
color: white;
padding: 5px 10px;
}
p.plain {
background-color: white;
color: blue;
}
blockquote {
border-left: 5px solid green;
padding-left: 20px;
}`;
sc.textContent = `function init() { //console.log("shadow script");
this.sh.querySelectorAll("DIV").forEach( v => v.addEventListener( "mousedown", (evt) => {
evt.stopPropagation();
//console.log( "shadow" );
let e = evt.target;
if ( e.matches( "p") ) {
e.classList.toggle("plain");
}
}, false ));
this.log = function(msg) { console.log(msg); };
}`;
tab.sh.appendChild(st);
tab.sh.appendChild(el_t1);
tab.sh.appendChild(sc);
init.call(tab);
//tab.log("hello");
//delete tab;
div {
border: 1px solid black;
margin-bottom: 20px;
}
blockquote {
border-left: 5px solid blue;
padding-left: 10px;
}
p {
padding: 5px 10px;
}
p.plain {
background-color: rgb(200,200,200);
color: purple;
}
<div class="light">
<h3>Light</h3>
<p>Opening Paragraph</p>
<blockquote>Hear this!</blockquote>
<p>Closing Paragraph</p>
</div>
<div class="light">
<h3>Light</h3>
<p>Opening Paragraph</p>
<blockquote>Did you hear that!</blockquote>
<p>Closing Paragraph</p>
</div>
<div class="shadow">
</div>
<template id="t1">
<div>
<h3>Shadow</h3>
<p>Opening Paragraph</p>
<blockquote>Heard from the Shadow?</blockquote>
<p>Closing Paragraph</p>
</div>
</template>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
