icon DOM操作の最適化によるJavaScriptチューニングにチャレンジ! (2013/09/26)
HTML5エキスパートで有名な吉川さん(同性w)からCodeIQの問題があったので挑戦!

DOM操作の最適化によるJavaScriptチューニングにチャレンジ!

オリジナル

    var button = document.querySelector('button'),
        ul = document.querySelector('#output'),
        itemCount = 0;

    function addItems() {
      for ( var i = 0; i < 10; i++ ) {
        itemCount++;
        ul.innerHTML += '<li><article class="item">'
                      + '<h1 class="title">アイテム' + itemCount + '</h1>'
                      + '<p class="detail">詳細' + itemCount + '</p>'
                      + '</article></li>';
      }
    }

30分くらいでざっとコーディングして提出

提出コード

    var button = document.querySelector('button'),
        ul = document.getElementById('output'),
        itemId = 0;

    var itemTemplate = '';
    var addCount = 10;
    var output = document.getElementById("output");

    function createItem() {
        itemId++;
        var item = new Object();
        item.title = 'アイテム' + itemId;
        item.detail = '詳細' + itemId;
        return item;
    }

    function loadItemTemplate(item) {
        var li = document.createElement('li'); 
        var article = document.createElement('article');
        var h1 = document.createElement('h1');
        var p = document.createElement('p');

        article.setAttribute('class', 'item');
        h1.setAttribute('class', 'title');
        p.setAttribute('class', 'detail');

        h1.textContent = item.title;
        p.textContent = item.detail;

        article.appendChild(h1);
        article.appendChild(p);
        li.appendChild(article);
        return li;
    }

    function addItems() {
      for ( var i = 0; i < addCount; i++ ) {
        itemTemplate = loadItemTemplate(createItem());
        document.getElementById('output').appendChild(itemTemplate);
      }
    }
テンプレートのHTML生成がループしてるので無駄だなと思いつつ、この程度だと計測時間が変わらなかったのでとりあえず。

丁寧にアドバイスを頂きました。

- Document Fragmentを経由
- getElementById()は高コストなのでキャッシュする

提出コード


    var button = document.querySelector('button'),
        ul = document.getElementById('output'),
        itemId = 0;

    var template;
    var addCount = 10;
    var li;
    var article;
    var h1;
    var p;

    loadItemTemplate();

    function createItem() {
        itemId++;
        var item = new Object();
        item.title = 'アイテム' + itemId;
        item.detail = '詳細' + itemId;
        return item;
    }

    function loadItemTemplate() {
        template = document.createElement('li'); 
        article = document.createElement('article');
        h1 = document.createElement('h1');
        p = document.createElement('p');

        article.setAttribute('class', 'item');
        h1.setAttribute('class', 'title');
        p.setAttribute('class', 'detail');

        article.appendChild(h1);
        article.appendChild(p);
        template.appendChild(article);
    }

    function bindItem(item) {
        h1.textContent = item.title;
        p.textContent = item.detail;
        var itemRow = template.cloneNode(true);
        ul.appendChild(itemRow);
    }

    function addItems() {
      for ( var i = 0; i < addCount; i++ ) {
          bindItem(createItem());
      }
    }

cloneNode()を利用してみたけど、なんかViewの分離がちょっと汚くなっちゃたかな?
insertNode()とかを使って、ツリーを操作した方がスムーズなのかも。