Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the clone() is too slow if the elements are inside a <form>?

Here you can find the whole example. By clicking on Click to Add you will clone 100 times the element trackOn; then it will be append to the table tracklistOn.

Unfortunatly, if these elements are inside a form you can see that the time is very high before the process is finish. If I remove the form, is quite immediate. Why this behaviour?

The whole code is here :

HTML

<div style="cursor:pointer;" id="addTr">Click to Add</div>   

<form action="index.php?status=add" method="POST">
    <table class="tracklistOn" cellpadding="0" cellspacing="0"></table>

    <table class="tracklistOff" style="display:none;">
        <tr class="trackOn"> 
            <td class="trackTime">
                <select class="trackTimeHH" name="hours[]">
                    <option>??</option><option value="">-</option><option value="00">00</option>  <option value="01">01</option>  <option value="02">02</option>  <option value="03">03</option>  <option value="04">04</option>  <option value="05">05</option>  <option value="06">06</option>  <option value="07">07</option>  <option value="08">08</option>  <option value="09">09</option>  <option value="10">10</option>  <option value="11">11</option>  <option value="12">12</option>  <option value="13">13</option>  <option value="14">14</option>  <option value="15">15</option>  <option value="16">16</option>  <option value="17">17</option>  <option value="18">18</option>  <option value="19">19</option>  <option value="20">20</option>  <option value="21">21</option>  <option value="22">22</option>  <option value="23">23</option>  <option value="24">24</option>  <option value="25">25</option>  <option value="26">26</option>  <option value="27">27</option>  <option value="28">28</option>  <option value="29">29</option>  <option value="30">30</option>  <option value="31">31</option>  <option value="32">32</option>  <option value="33">33</option>  <option value="34">34</option>  <option value="35">35</option>  <option value="36">36</option>  <option value="37">37</option>  <option value="38">38</option>  <option value="39">39</option>  <option value="40">40</option>  <option value="41">41</option>  <option value="42">42</option>  <option value="43">43</option>  <option value="44">44</option>  <option value="45">45</option>  <option value="46">46</option>  <option value="47">47</option>  <option value="48">48</option>  <option value="49">49</option>  <option value="50">50</option>  <option value="51">51</option>  <option value="52">52</option>  <option value="53">53</option>  <option value="54">54</option>  <option value="55">55</option>  <option value="56">56</option>  <option value="57">57</option>  <option value="58">58</option>  <option value="59">59</option> 
                </select>
            </td>            

            <td class="trackTime">    
                <select class="trackTimeMM" name="minuts[]">
                    <option>??</option><option value="">-</option><option value="00">00</option>  <option value="01">01</option>  <option value="02">02</option>  <option value="03">03</option>  <option value="04">04</option>  <option value="05">05</option>  <option value="06">06</option>  <option value="07">07</option>  <option value="08">08</option>  <option value="09">09</option>  <option value="10">10</option>  <option value="11">11</option>  <option value="12">12</option>  <option value="13">13</option>  <option value="14">14</option>  <option value="15">15</option>  <option value="16">16</option>  <option value="17">17</option>  <option value="18">18</option>  <option value="19">19</option>  <option value="20">20</option>  <option value="21">21</option>  <option value="22">22</option>  <option value="23">23</option>  <option value="24">24</option>  <option value="25">25</option>  <option value="26">26</option>  <option value="27">27</option>  <option value="28">28</option>  <option value="29">29</option>  <option value="30">30</option>  <option value="31">31</option>  <option value="32">32</option>  <option value="33">33</option>  <option value="34">34</option>  <option value="35">35</option>  <option value="36">36</option>  <option value="37">37</option>  <option value="38">38</option>  <option value="39">39</option>  <option value="40">40</option>  <option value="41">41</option>  <option value="42">42</option>  <option value="43">43</option>  <option value="44">44</option>  <option value="45">45</option>  <option value="46">46</option>  <option value="47">47</option>  <option value="48">48</option>  <option value="49">49</option>  <option value="50">50</option>  <option value="51">51</option>  <option value="52">52</option>  <option value="53">53</option>  <option value="54">54</option>  <option value="55">55</option>  <option value="56">56</option>  <option value="57">57</option>  <option value="58">58</option>  <option value="59">59</option>             
                </select>    
            </td>            

            <td class="trackTime">
                <select class="trackTimeSS" name="seconds[]">
                    <option>??</option><option value="">-</option><option value="00">00</option>  <option value="01">01</option>  <option value="02">02</option>  <option value="03">03</option>  <option value="04">04</option>  <option value="05">05</option>  <option value="06">06</option>  <option value="07">07</option>  <option value="08">08</option>  <option value="09">09</option>  <option value="10">10</option>  <option value="11">11</option>  <option value="12">12</option>  <option value="13">13</option>  <option value="14">14</option>  <option value="15">15</option>  <option value="16">16</option>  <option value="17">17</option>  <option value="18">18</option>  <option value="19">19</option>  <option value="20">20</option>  <option value="21">21</option>  <option value="22">22</option>  <option value="23">23</option>  <option value="24">24</option>  <option value="25">25</option>  <option value="26">26</option>  <option value="27">27</option>  <option value="28">28</option>  <option value="29">29</option>  <option value="30">30</option>  <option value="31">31</option>  <option value="32">32</option>  <option value="33">33</option>  <option value="34">34</option>  <option value="35">35</option>  <option value="36">36</option>  <option value="37">37</option>  <option value="38">38</option>  <option value="39">39</option>  <option value="40">40</option>  <option value="41">41</option>  <option value="42">42</option>  <option value="43">43</option>  <option value="44">44</option>  <option value="45">45</option>  <option value="46">46</option>  <option value="47">47</option>  <option value="48">48</option>  <option value="49">49</option>  <option value="50">50</option>  <option value="51">51</option>  <option value="52">52</option>  <option value="53">53</option>  <option value="54">54</option>  <option value="55">55</option>  <option value="56">56</option>  <option value="57">57</option>  <option value="58">58</option>  <option value="59">59</option>
                </select>
            </td>            
        </tr>
    </table>        
</form>

jQuery

$('#addTr').click(function () {
    var savedTrackOn=$('.tracklistOff').find('.trackOn');
    for(i=0; i<100; i++) {
        savedTrackOn.clone().appendTo($('.tracklistOn'));
    }
});

How can I fix this problem?

EDIT

Tried it on Firefox 6.0, and the problems is vanished :O Only old version and chrome+IE? Why?

like image 822
markzzz Avatar asked Aug 28 '11 14:08

markzzz


2 Answers

The documentation clearly states the following:

The .clone() method performs a deep copy of the set of matched elements, meaning that it copies the matched elements as well as all of their descendant elements and text nodes. When used in conjunction with one of the insertion methods, .clone() is a convenient way to duplicate elements on a page

Knowing this, it would be wise to limit the amount of deep traversal expected of .clone().

This issue is completely unrelated to jQuery, as illustrated here where I've swapped out your code with host API code and the perceived performance issue still exists.

Lastly, I was able to identify another "work around" to this issue that would lead us to believe that the issue also lies in appending the new nodes, take a look and you'll see that moving the destination element out of the form also improves the performance drastically.

like image 173
Rick Avatar answered Sep 25 '22 16:09

Rick


This is just to flesh out my comment from earlier, and echo what Rick said.

I've tried the following (in Safari):

  • Using plain javascript (no jQuery): Still slow
  • Using divs instead of tables: Still slow
  • Using innerHTML instead of .clone()/cloneNode(): Still slow
  • Moving the template out of the form: Still slow
  • Building the elements from scratch instead of cloning: Still slow
  • Appending everything to a temporary element outside the form, and moving it afterwards: Still slow
  • Hiding the form while appending elements: Still slow
  • Removing name attributes on the input elements before cloning/copying/whatever: Still slow
  • Removing the attributes on the form itself: Still slow
  • Using plain numbering instead of list-style naming (i.e. "nameX" instead of "name[]"): Still slow

So, again, as long as you're appending those select inputs to a form element, it'll be slow.

But as Rick suggested, you can append the inputs to an element outside the form, and use JS to serialize and submit them.

Alternatively, you can append input type="hidden" elements to the form (which is fast) to the form, while appending the actual select elements to something outside the form. Then you could conceivably use event listeners to make the hidden inputs mirror the values of the selects. The hidden inputs will be submitted with the form, while the selects just function as a user interface.

Another option would be to have the dropdowns in the markup to begin with (which I suspect the browser would render fast), but having them be disabled and hidden. Then use javascript to unhide and enable the dropdowns when needed. I don't know if this will cause a slowdown too, but since new elements aren't being appended, it should be faster.

Still doesn't explain the slowness (or why it's apparently fast in FF6)

like image 32
Flambino Avatar answered Sep 26 '22 16:09

Flambino