Can my responsive-tables JS code be made more performant? I was using dataTables.net's responsive plugin before this, and am happy to say that my (much simpler) code runs about 5 times quicker than that did.  On my machine the fiddle averages about 50ms versus 250ms if I use DT responsive.

Is there anything I should do to improve performance of my code? Can it be made better?  I'm FAR from a JS expert, as I'm sure it shows.  I'm very happy to drop jQuery if it can be done better without!

Here's a working JS fiddle.

function initResponsiveTables() {
    //does this enhance performance at all?
    'use strict';

    //get an array of &lt;th&gt; elements
    var th = $('th');

    //initialise in top scope
    var priorities = [];

    //iterate over the &lt;th&gt;s, extracting their column priorities
    th.each(function (index) {
        var priority = th[index].getAttribute('data-priority');

        //TODO: this seems very messy, I feel there must be a cleaner way?
        if (priorities[priority] === undefined) {
            priorities[priority] = index;
        } else {
            priorities[priority] += ',' + index;
        }
    });

    //clean up the array so we have consecutive indices
    priorities = priorities.filter(function (x) {
        return x !== undefined &amp;&amp; x !== null;
    });

    //initialise all of these outside of the loop
    var sCols = '';
    var aCols = [];
    var aSelectors = [];
    var sSelectors = '';
    var i;

    //while the table is wider than the window, and there's still columns to remove
    while ($('#table').width() &gt; $(window).width() - 40 &amp;&amp; priorities.length &gt; 0) {
        //get the lowest priority
        sCols = (priorities.pop() + '');

        //split it, in case we have more than one column on the same priority
        //in this case we prefer to remove them as a group, rather than one at a time
        aCols = sCols.split(',');

        //clear the array from previous iteration
        aSelectors = [];
        for (i = 0; i &lt; aCols.length; i++) {
            //build up the jQuery selectors
            aSelectors.push('td:nth-child(' + aCols[i] + '), th:nth-child(' + aCols[i] + ')');
        }

        //make jQuery selector string
        sSelectors = aSelectors.join(', ');

        //hide relevant columns
        $(sSelectors).css('display', 'none');
    }
}

var start = performance.now();;

initResponsiveTables();

alert(performance.now() - start);
I know the people on here can do a way better job, but here it is without jQ and those array function things. Hopefully someone here will give you some real advise.  I just wanted to get rid of the jQ.

One note, you don't need to array.join strings any more.

...only found that out about a year ago myself.

Your main bottle necks will be in how you alter/touch the dom, but I'm no good at those points... google I guess.

All this does give you more speed, but I bet theres people here that would hate me not using array function stuff.  But you seemed to be into speed so that's what I gave you.  Me I can go either way...speed this, comfort that.  

function initResponsiveTables() {
  //does this enhance performance at all?
  'use strict';

  //get an array of &lt;th&gt; elements
  var th = document.getElementsByTagName('th');

  //initialise in top scope
  var priorities = [];

  //iterate over the &lt;th&gt;s, extracting their column priorities
  for (var i = 0, end = th.length; i &lt; end; i += 1) {

    var priority = th[i].getAttribute('data-priority');

    //TODO: this seems very messy, I feel there must be a cleaner way?
    if (priorities[priority] === undefined) {
      priorities[priority] = i;
    } else {
      priorities[priority] += ',' + i;
    }
  }

  for (var spot = 0, i = 0, end = priorities.length, x; i &lt; end; i += 1) {
    x = priorities[i];
    if (x !== undefined &amp;&amp; x !== null) {
      priorities[spot] = x;
      spot += 1;
    }

  }
  priorities.length = spot;

  //initialise all of these outside of the loop
  var sCols = '';
  var aCols = [];
  var aSelectors = [];
  var sSelectors = '';
  var i;

  var table = document.getElementById('table');

  while (table.getBoundingClientRect().width &gt; window.document.documentElement["clientWidth"] - 40 &amp;&amp; priorities.length &gt; 0) {

    //get the lowest priority
    sCols = (priorities.pop() + '');

    //split it, in case we have more than one column on the same priority
    //in this case we prefer to remove them as a group, rather than one at a time
    aCols = sCols.split(',');

    //clear the string from previous iteration
    aSelectors = '';
    for (i = 0; i &lt; aCols.length - 1; i += 1) {
      //build up the selectors
      aSelectors += ('td:nth-child(' + aCols[i] + '), th:nth-child(' + aCols[i] + ')') + ', ';
    }
    aSelectors += ('td:nth-child(' + aCols[i] + '), th:nth-child(' + aCols[i] + ')');

    var els = table.querySelectorAll(aSelectors);
    for (var i = 0, end = els.length; i &lt; end; i += 1) {
      els[i].style.display = 'none';
    }
  }
}

var start = performance.now();;

initResponsiveTables();

alert(performance.now() - start);


EDIT:
Couldn't sleep its like 40 degrees C here right now so thought Id make you an example to show the difference when you dont thrash the dom.  I think the technical term (bad memory) would be trying to avoid reflows.  

Where yours is is pretty obvious, this....
while (table.getBoundingClientRect().width &gt; window.document.documentElement["clientWidth"] - 40 &amp;&amp; priorities.length &gt; 0) {
...specificly....
table.getBoundingClientRect().width for sure and maybe window.document.documentElement["clientWidth"]
...combined with...
els[i].style.display = 'none';  

Your, in a loop, changing the dom and then asking for a prop that definitely causes a reflow/repaint/wotevaitscalled if the dom has changed since last call and that stuff is real costly.  

So what if we knew the width of the cells and only had to get the width of the table and window once?  Well youd end up with code like below and if you test it youll see it is faster, ESPECIALLY in FireFox (didnt test IE).  

I pre picked the width of the cells, but you could look into maybe getting it from the already rendered table (hate that by the way) or other options, or just stick with a set width which the browser would like anyway (easier to paint).  

http://plnkr.co/edit/oeJpGK?p=preview      I prfr plnkr ;)  

function initResponsiveTables() {
  //does this enhance performance at all?
  'use strict';

  var th = document.getElementsByTagName('th');
  var priorities = [];
  for (var end = 0, i = th.length - 1; i &gt;= end; i -= 1) {

    var priority = th[i].getAttribute('data-priority');

    //TODO: this seems very messy, I feel there must be a cleaner way?
    if (priorities[priority] === undefined) {
      priorities[priority] = [
        i
      ];
    } else {
      priorities[priority].push(i);
    }
  }

  var removeCols = [];
  // Looking at the idea of having a set width
  // Im not great at html, depending on how tables work you might be able to get the width after the table is created instead of using a set width. worse come to worse scan each row for biggest cell
  // its also set in the css
  var colWidth = 85;

  var table = document.getElementById('table');
  var tableWidth = table.getBoundingClientRect().width;
  var targetDiff = table.getBoundingClientRect().width - window.document.documentElement["clientWidth"] - 40;
  var currentDiff = 0;
  var colIndex = priorities.length - 1;
  var cols;

  if (targetDiff &gt; 0) {
    // var atLeast = Math.ceil(diff / colWidth); // how many cols to remove
    while (currentDiff &lt; targetDiff &amp;&amp; colIndex &gt;= 0) {

      cols = priorities[colIndex];

      if (!cols) {
        //skip sparse bits
        while (cols === undefined &amp;&amp; colIndex &gt;= 0) {
          cols = priorities[colIndex--];
        }
      }

      if (cols) {
        cols.forEach(function(index) {
          table.tHead.rows[0].children[index].style.display = 'none';
          for (var i = 0, end = table.children[1].children.length; i &lt; end; i += 1) {
            var row = table.children[1].children[i];
            row.children[index].style.display = 'none';
          }
        });
        currentDiff += colWidth * cols.length;
      }
      colIndex--;
    }
  }
}

var start = performance.now();;

initResponsiveTables();

alert(performance.now() - 

start);