Endless loop through additional DOM element

Without using the formula for using XXX

This question is not meant to find a practical solution through a framework. Answer using frame XXX, or is it that simple in frame XXX, or why not use this XXX frame ??? does not answer the question.

I have a feature designed to run after the page load performShim

. This function iterates over all DOM elements that are tags span

, checks to see if they have an className

of shim

, and if so, calls it shim

, passing it the reference of the matched element.

My goal was to add another span

containing one iframe

to the element that is being passed to shim


With the code I've written so far, I can add to the parent just fine. However, if I comment out the line append

and instead try the prefix line the browser is hanging in a supposedly infinite loop.

It is not easy for me to understand why this is so.

function shim( element ) {      
    var iframe = document.createElement('iframe');
    iframe.setAttribute( 'frameborder', '0' );
    iframe.setAttribute( 'scrolling', 'no' );
    iframe.setAttribute( 'align', 'bottom' );
    iframe.setAttribute( 'marginheight', '0' );
    iframe.setAttribute( 'marginwidth', '0' );
    iframe.setAttribute( 'src', "javascript:'';" ); 

    var span = document.createElement('span');

    //element.parentNode.insertBefore(span,element); //causes infinite loop?

    element.parentNode.appendChild(span); //this line works OK

    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'inline';
    var width = element.offsetWidth;
    var height = element.offsetHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;

    iframe.style.width = (width-6) + 'px';
    iframe.style.height = (height-6) + 'px';


function performShim() {
    var children = document.getElementsByTagName("span");   
    for( var i = 0; i < children.length; i++ ) {
        if( children[i].className == "shim" ) {



source to share

1 answer

The A NodeList

(for example, the returned one document.getElementsByTagName

) is usually a live list - changes made to the DOM are also reflected in it. So every time you add span

before the current, you expand the list with one element and move the current element by one, and the next iteration takes you back to the node you just finished.

You have some easy workarounds for this ...

  • Kill the counter when you add node. (Awful, and if you ever add something instead span

    , you end up missing nodes and it won't be obvious why.)

  • Copy list to array and iterate over the array. You can do it with something like children = [].slice.call(children, 0);

    (more often) or
    children = Array.apply(window, children);


  • Use document.querySelectorAll

    one that returns you a NodeList, which won't work. (And even if it was live, in which case you could choose 'span.shim'

    , and the inserted gaps did not appear in this case.)

  • Iterations backward (from children.length - 1

    to 0).



All Articles