Skip to content
Astera Technology

Choose between a snapshot and a live DOM collection

Compare an old selector result with a collection that updates when nodes change.

Download complete case notes and answer keys ↓

Inspect the fixed example

Start with one paragraph. Capture querySelectorAll and getElementsByTagName results, append a second paragraph, then query again.

Complete body and fixed script
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>First note</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const snapshot=list.querySelectorAll('p');const live=list.getElementsByTagName('p');const added=document.createElement('p');added.textContent='Second note';list.append(added);
const result={snapshot:snapshot.length,live:live.length,current:list.querySelectorAll('p').length};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>
Exact console output
{"snapshot":1,"live":2,"current":2}
Inputs and native results
InspectionSupplied input or actionResult
querySelectorAll before append1 paragraphsnapshot: 1
getElementsByTagName before append1 paragraph, then appendlive: 2
Fresh queryAfter appendcurrent: 2

Follow the native mechanism

querySelectorAll returns a static NodeList: its membership remains the original matching nodes. getElementsByTagName returns a live HTMLCollection. Static membership is not an immutable snapshot of each node’s text or properties; retained nodes remain the same objects.

Compare the material alternative

Removing entries while indexing a live collection shifts later entries. This loop is bounded at three passes; it removes A and C but skips B.

Fresh counterexample source
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>A</p><p>B</p><p>C</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const live=list.getElementsByTagName('p');const removed=[];for(let index=0;index<3&&index<live.length;index++){removed.push(live[index].textContent);live[index].remove();}
const result={removed,remaining:[...live].map(node=>node.textContent)};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>
Counterexample output
{"removed":["A","C"],"remaining":["B"]}

Work the boundary

How can all three supplied paragraphs be removed without index shifting?

Show the worked answer

Iterate a snapshot of the three node references. The current DOM becomes empty, although that static list still retains the three removed nodes.

Fresh boundary source
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<section id="list"><p>A</p><p>B</p><p>C</p></section><output id="result"></output>
<script>const list=document.querySelector('#list');const snapshot=list.querySelectorAll('p');for(const node of snapshot)node.remove();
const result={snapshot:snapshot.length,current:list.querySelectorAll('p').length,firstConnected:snapshot[0].isConnected};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>
Boundary output
{"snapshot":3,"current":0,"firstConnected":false}

Original example files