JavaScriptでページ遷移用のナビゲーションを作っていたのだが、リンクと半角スペース(テキストノード)とを交互に挿入するような実装にしていると、なぜか異様に時間がかかってしまう(数百個程度のノード挿入に、数秒要する)。
どうやら、ナビゲーションのノードがDOMツリー上にあるとこうなるようで、いったんDOMツリーから切り離した状態で作成し、最後にDOMツリーに戻すようにすると、ほとんど時間はかからない。でもなぜ……?
さんざん悩んだが、結局はとある拡張機能が原因だった、というオチ(今回の場合ははちまバスター)。
もっと早くに、シークレットウィンドウで調べておくべきだった……。
【追記】なお、はちまバスターは早々に改修された。
テスト
function test_add_nodes( options ) { if ( ! options ) { options = {} } var parent_node = ( options.parent_node ) ? options.parent_node : document.body, before_processing = !! ( options.before_processing ), node_number = ( 0 < options.node_number ) ? options.node_number : 300, exclude_link = !! ( options.exclude_link ), exclude_text = !! ( options.exclude_text ); var container = document.createElement('div'), link_node_template = document.createElement('a'); text_node_template = document.createTextNode(''); before_time = new Date().getTime(); if ( parent_node && before_processing ) { parent_node.insertBefore( container, parent_node.firstChild ); } for ( var ci=0; ci < node_number; ci++ ) { if ( ! exclude_link ) { var link_node = link_node_template.cloneNode( true ); link_node.href = '#'; link_node.innerHTML = ci; container.appendChild( link_node ); } if ( ! exclude_text ) { var text_node = text_node_template.cloneNode( true ); text_node.textContent = '*'; container.appendChild( text_node ); } } if ( parent_node && ( ! before_processing ) ) { parent_node.insertBefore( container, parent_node.firstChild ); } var after_time = new Date().getTime(), elapsed_time = ( after_time - before_time ); return elapsed_time; } function log_result( test_name, elapsed_time ) { console.log( test_name + ' : ' + ( elapsed_time / 1000.0) + ' sec' ); } // DIV要素にリンクやテキストノードを一通り追加してから、DOMツリーに挿入 log_result( 'after , text only', test_add_nodes( { before_processing : false, exclude_link : true, exclude_text : false } ) ); log_result( 'after , link only', test_add_nodes( { before_processing : false, exclude_link : false, exclude_text : true } ) ); log_result( 'after , both ', test_add_nodes( { before_processing : false, exclude_link : false, exclude_text : false } ) ); // DIV要素をDOMツリーに予め挿入してから、リンクやテキストノードを追加 log_result( 'before, text only', test_add_nodes( { before_processing : true, exclude_link : true, exclude_text : false } ) ); log_result( 'before, link only', test_add_nodes( { before_processing : true, exclude_link : false, exclude_text : true } ) ); log_result( 'before, both ', test_add_nodes( { before_processing : true, exclude_link : false, exclude_text : false } ) );
拡張機能有効時
after , text only : 0.003 sec after , link only : 0.057 sec after , both : 0.054 sec before, text only : 0.04 sec before, link only : 0.04 sec before, both : 6.856 sec // これは酷い
拡張機能無効時
after , text only : 0.002 sec after , link only : 0.005 sec after , both : 0.01 sec before, text only : 0.027 sec before, link only : 0.045 sec before, both : 0.05 sec