2009-07-28 4 views
1

사진 작업소에서 프린터에서 처리 할 인쇄 명령을 시작하는 웹 도구를 만듭니다.은 성능이 나쁜 jQuery 스크립트입니다.

오래된 Mac의 스크립트에서 성능이 좋지 않습니다. 스크립트에 성능이 낮은 부분이 있는지 궁금합니다.

저 성능 부품이 보이십니까?

들으, 최대

$(function() { 

/* when start button is clicked */ 
$('.start_btn').click(function() { 

    /* remove all previous input fields */ 
    $("#dialog_fieldset").children().remove(); 

    /* save id */ 
    id = $(this).attr('name'); 

    /* get data from db */ 
    $.post("inc/get_start_order_infos.inc.php", { id: id }, 

     /* Callback */ 
     function(data){ 

      /* make data globally available */ 
      daten = data; 

      /* build the var 'infos_html' */ 
      var infos_html = '<label for="kunden_nr">Kunden-Nr.</label><input type="text" name="kunden_nr" id="kunden_nr" '; 
      infos_html += 'value="' + data.kunden_nr + '" class="text ui-widget-content ui-corner-all" />'; 
      infos_html += '<label for="sort">Sort</label><input type="text" name="sort" id="sort" value="'; 
      infos_html += data.sort_nr + '" class="text ui-widget-content ui-corner-all" />'; 

      /* append infos_html to the fieldset */ 
      $('#dialog_fieldset').append(infos_html); 

      /* Code Index */ 
      anzahlCodes = 1; 

      /* For each element within the sub array codes */ 
      for(e in data.codes){ 

       /* build the var 'code_html' */ 
       var code_html = '<label for="code' + anzahlCodes + '">Code ' + anzahlCodes; 
       code_html += '</label><input type="text" name="code' + anzahlCodes + '" id="code' + anzahlCodes; 
       code_html += '" value="' + data.codes[e] + '" class="text ui-widget-content ui-corner-all" />'; 

       /* append code_html to the fieldset */ 
       $('#dialog_fieldset').append(code_html); 
       anzahlCodes++; 
      } 

      $('#dialog').dialog('open'); 
      $('#kunden_nr').select(); 

    }, "json"); 

    return false; 
}); 

$("#dialog").dialog({ 
    bgiframe: false, 
    autoOpen: false, 
    height: 350, 
    modal: true, 
    buttons: { 
     'Auftrag starten': function() { 

      /* close dialog */ 
      $(this).dialog('close'); 

      /* create the info array to be submitted */ 
      var arr_infos = new Array(); 
      arr_infos[0] = id; 
      arr_infos[1] = $('#kunden_nr').attr('value'); 
      arr_infos[2] = $('#sort').attr('value'); 

      /* write inputs into the str_codes */ 
      var str_codes = ""; 
      for (var i=1; i < anzahlCodes; i++){ 
       var cde = '#code' + i; 
       if(i == 1){ 
        str_codes += $(cde).attr('value'); 
       } 
       else{ 
        str_codes += "<--->" + $(cde).attr('value'); 
       } 
      } 


      /* execute start */ 
      $.post("inc/start_orders.inc.php", { 'corrected_infos[]':arr_infos, 'corrected_codes': str_codes }, 

       /* Callback */ 
       function(data){ 
        $('#notice').remove(); 

        /* if start was successful */ 
        if (data.mstype == 'success'){ 

         /* the pressed button */ 
         btn = ".start_btn[name=" + id + "]"; 
         /* the tr where the button is inside */ 
         tr = $(btn).parent().parent(); 
         /* remove red */ 
         $(tr).removeClass('rot'); 

         /* set text of Kunden-Nr. td */ 
         $(tr).children().eq(3).text(arr_infos[1]); 

         /* set text of Sort td */ 
         $(tr).children().eq(4).text(arr_infos[2]); 

         /* set text of Code td */ 
         $(tr).children().eq(5).text(str_codes); 

         /* set text of start td */ 
         $(tr).children().eq(8).text('ja'); 

         /* prepend notice */ 
         $("#outline").prepend("<div id='notice'>" + data.ms + "</div>"); 
        } 

        /* if not successful */ 
        else { 
         $("#outline").prepend("<div id='notice' class='notice_err'>" + data.ms + "</div>"); 
        } 
       }, "json"); 
     }, 
     'Abbrechen': function() { 
      $(this).dialog('close'); 
     } 
    } 
}); 

답변

6

의견은 //++으로 표시된 코드에 나와 있습니다. 일반적으로 JavaScript는 가능한 한 DOM을 검색하거나 변경할 때 더 빠릅니다. 우려의

주요 포인트는 루프와이 코드를 테스트하지 않았습니다 $(tr).

당신의 반복 사용에 있습니다.

$(function() { 
    //++ jQuery doesn't cache this call, so it has to search the DOM each time. 
    //++ I've moved any node that is requested more than once here 
    var dialog_fieldset_node = $("#dialog_fieldset"), 
     dialog_node   = $("#dialog"), 
     kunden_nr_node  = $("#kunden_nr"), 
     outline_node   = $("#outline"); 
    //++ variables that you're using as globals I've moved here so that they can be shared 
    //++ between the event handlers, but aren't poluting the global scope. They are accessible 
    //++ to each event handler via the closure property of this annonymous function. 
    var id = null; 
    //++ Since you're creating the code <INPUT> nodes, store a refernce to them at that time 
    //++ instead of having to find them in the DOM again later. Now, anzahlCodes doesn't need 
    //++ to be available to both handlers. 
    var code_input_nodes = []; 

    /* when start button is clicked */ 
    $('.start_btn').click(function() { 
     /* remove all previous input fields */ 
     dialog_fieldset_node.children().remove(); 

     /* save id */ 
     id = $(this).attr('name'); 

     /* get data from db */ 
     $.post("inc/get_start_order_infos.inc.php", { id: id }, 
      /* Callback */ 
      function(data){ 
       /* make data globally available */ 
       daten = data; 

       /* append infos_html to the fieldset */ 
       //++ No need to build a string in a variable that you're only going to use once. You might want 
       //++ to build this out using DOM methods as I did below. Since its only done once, there might 
       //++ not be a difference performancy wise 
       dialog_fieldset_node.append(
        '<label for="kunden_nr">Kunden-Nr.</label><input type="text" name="kunden_nr" id="kunden_nr" ' + 
        'value="' + data.kunden_nr + '" class="text ui-widget-content ui-corner-all" />' + 
        '<label for="sort">Sort</label><input type="text" name="sort" id="sort" value="' + 
        data.sort_nr + '" class="text ui-widget-content ui-corner-all" />' 
       ); 


       //++ 1) `var e` to keep `e` from begin global. If you want this side effect, you should be explicit about it. 
       //++ 2) Create nodes via DOM methods to avoid running the HTML parser. node variables are defined outside of the 
       //++ loop to avoid overhead of instantiation and scope-chain modification (minimal, but effective for large sets 
       //++ of iterations. 
       //++ 3) Append created nodes to a document fragment and then append the fragment to the `dialog_fieldset_node` to 
       //++ avoid multiple, unnecessary DOM tree reflows (which are slow). 
       var fragment  = document.createDocumentFragment(), 
        label_node = null, 
        input_node = null; 
        anzahlCodes = 0; 
       //++ Seems this needs to be reset everytime 
       code_input_nodes = []; 

       /* For each element within the sub array codes */ 
       for(var e in data.codes){ 
        label_node = document.createElement("LABEL"); 
        label_node.setAttribute("for", anzahlCodes); 
        label_node.innerHTML = "Code " + anzahlCodes; 

        input_node = document.createElement("INPUT"); 
        input_node.setAttribute("type", "text"); 
        input_node.setAttribute("name", "code" + anzahlCodes); 
        input_node.setAttribute("id", "code" + anzahlCodes); 
        input_node.setAttribute("class", "text ui-widget-content ui-corner-all"); 
        input_node.setAttribute("value", data.codes[e]); 

        //++ store a reference for later use 
        code_input_nodes.push(input_node); 

        /* append code_html to the fieldset */ 
        fragment.appendChild(label_node); 
        fragment.appendChild(input_node); 
        anzahlCodes++; 
       } 
       dialog_fieldset_node.append(fragment); 

       dialog_node.dialog('open'); 
       kunden_nr_node = $("#kunden_nr"); 
       kunden_nr_node.select(); 

      }, 
      "json" 
     ); 

     return false; 
    }); 

    dialog_node.dialog({ 
     bgiframe: false, 
     autoOpen: false, 
     height: 350, 
     modal: true, 
     buttons: { 
      'Auftrag starten': function() { 
       /* close dialog */ 
       $(this).dialog('close'); 

       /* create the info array to be submitted */ 
       var arr_infos = [id, kunden_nr_node.attr('value'), $('#sort').attr('value')]; 

       /* write inputs into the str_codes */ 
       var str_codes = ""; 
       for (var i in code_input_nodes) { 
        str_codes += (i ? "" : "<--->") + code_input_nodes[i].attr('value'); 
       } 


       /* execute start */ 
       $.post("inc/start_orders.inc.php", { 'corrected_infos[]':arr_infos, 'corrected_codes': str_codes }, 
        /* Callback */ 
        function(data){ 
         $('#notice').remove(); 

         /* if start was successful */ 
         if (data.mstype == 'success'){ 
          /* the tr where the button is inside */ 
          //++ 1) Was this intentionally global? Global variables are the slowest to access because they 
          //++ are at the end of the scope-chain (which *sometimes* makes a difference, depending on depth). 
          //++ 2) Instead of wrapping `tr` in `$()` every time you use it, just do it once. 
          var tr = $(
            $(".start_btn[name=" + id + "]").parent().parent() 
           ); 
          //++ Avoid calling `.children()` multiple times, just do it once. 
          var tr_children = tr.children(); 

          /* remove red */ 
          tr.removeClass('rot'); 

          /* set text of Kunden-Nr. td */ 
          tr_children.eq(3).text(arr_infos[1]); 

          /* set text of Sort td */ 
          tr_children.eq(4).text(arr_infos[2]); 

          /* set text of Code td */ 
          tr_children.eq(5).text(str_codes); 

          /* set text of start td */ 
          tr_children.eq(8).text('ja'); 

          /* prepend notice */ 
          outline_node.prepend("<div id='notice'>" + data.ms + "</div>"); 
         } 

         /* if not successful */ 
         else { 
          outline_node.prepend("<div id='notice' class='notice_err'>" + data.ms + "</div>"); 
         } 
        }, 
        "json" 
       ); 
      }, 

      'Abbrechen': function() { 
       $(this).dialog('close'); 
      } 
     } 
    }); 
}); 

도움이 되었기를 바랍니다.

+0

와우 ... 놀랄만 한 대답 ... 지금 자세히 읽어 보겠습니다. 고마워! – Max

+0

저스틴, 오류가 발생했습니다 : code_input_nodes [i] .attr은 함수가 아닙니다 (라인 107) 해당 라인의 if 문이 올바른지 궁금합니다! Thx에 대한 모든 댓글과 그 멋진 도움! – Max

+0

그래서 내가 TR에 대해 말한 것과 간단한 문자열 조작을 DOM 요소 조작으로 변경했다고 말했어 ... 어떻게 더 빠릅니까? –

2

헤이 최대. 아직 설치하지 않았다면 FirefoxFirebug을 설치하십시오. 그런 다음 Javascript 프로파일 링 기능을 사용하여 속도 저하가 정확히 어디에서 발생했는지 확인할 수 있습니다.

파이어 버그가있는 프로파일 링에 대해서는 tutorial이 좋습니다.

행운을 빈다.

+0

느린 기능을 감지하는 데 도움이되는 동안, 이유를 설명하는 데는 도움이되지 않습니다. –

+0

그게 바로 두뇌입니다. – hobodave

+0

저스틴, 코드를 고치고 코드를 살펴보기 전에 어느 부분인지 알아야합니다. 코드가 어디에 있는지는 분명하지 않습니다 ... –

1

코드를 보면서 발생하는 가장 큰 실수는 행 자식 요소를 다시 선택하는 두 번째 콜백 (맨 아래)에 있습니다. 당신은 정말로 그 공통 쿼리 결과를 변수에 할당하고 그것을 사용해야합니다. 나는 당신이 성능면에서 향상을 보았다고 상상할 것입니다. 이것은 내가 그것을 바꿀 것입니다 방법은 다음과 같습니다

그 외에는
/* beginning of callback code */ 

if (data.mstype == 'success') { 

    /* the pressed button */ 
    btn = $(".start_btn[name=" + id + "]"); 
    /* the tr where the button is inside */ 
    tr = $(btn).parent().parent(); 
    /* remove red */ 
    tr.removeClass('rot'); 

    /***** This is the change *****/ 
    var children = $(tr).children(); 

    /* set text of Kunden-Nr. td */ 
    children.eq(3).text(arr_infos[1]); 

    /* set text of Sort td */ 
    children.eq(4).text(arr_infos[2]); 

    /* set text of Code td */ 
    children.eq(5).text(str_codes); 

    /* set text of start td */ 
    children.eq(8).text('ja'); 
    /* prepend notice */ 
    $("#outline").prepend("<div id='notice'>" + data.ms + "</div>"); 
} 

/* end of callback code */ 

당신이 나쁜 성능에서 오는 다른 사람들이 가지고 그것을 위해 당신이 방화범을 사용할 수 있다는 것입니다 WHERE 정확하게에 관해서는 구체적으로해야 할 것 지적했다.

+0

'$ (tr)'을 반복적으로 사용하면 아래쪽에서 가장 큰 문제는 두 개의 루프입니다. 첫 번째는 HTML 구문 분석기를 호출하여 반복 할 때마다 DOM을 재구성하고 두 번째 모듈은 반복 할 때마다 DOM을 검색한다. –

+0

당신이 제안한 것처럼 dom에서 노드를 만드는 것보다 추악하고 가장 우아한 방법은 빠르지 만, append()는 dom을 조작하는 것이 아니라 –

+0

dom 노드에 여러 항목을 추가하는 것은 추가하는 것보다 빠르지 않다. 조각에. 또한 그는 $ ("# someid")를 여러 번 호출하여 배열을 생성 할 때 배열에 저장하는 것보다 느리고 배열에서 나중에 간단히 액세스합니다. –

0

dialog_fieldset_node.children().remove();은 empty();를 통해보다 적절하게 처리됩니다. dialog_fieldset_node.empty();

관련 문제