Пожалуйста, помогите мне изменить этот код JQuery - PullRequest
0 голосов
/ 28 января 2010

Мне нужно, чтобы этот jquery работал намного быстрее, я не создавал все эти функции, но мне нужны их методы, чтобы делать живые переводы содержимого страницы.

Так что я был бы признателен за любые предложения по рефакторингу для лучшей производительности, код ниже.


/* function 1 read json into array */
/* function 2 loop through array */
/* function 3 replace text nodes based on data from looped array */

var en_lang = new Array();
var fr_lang = new Array();
var frca_lang = new Array();
var my_data = null;
var en_count = 1;
var fr_count = 1;
var frca_count = 1;

if(typeof(language) != "undefined"){
    var language = 'frca';
}

function replaceText(oldText, newText, node){ 
  node = node || document.body; // base node 

  var childs = node.childNodes, i = 0;

  while(node = childs[i]){ 
    if (node.nodeType == 3){ // text node found, do the replacement
      if (node.textContent) {
        node.textContent = node.textContent.replace(oldText, newText);
      } else { // support to IE
        node.nodeValue = node.nodeValue.replace(oldText, newText);
      }
    } else { // not a text mode, look forward
      replaceText(oldText, newText, node); 
    } 
    i++; 
  } 
}
function parsejSON(my_data) {
    /* THIS PART GRABS DATA FROM TOP OF JSON FILE */

    /* grab recordcount */
    var recordcount = my_data.recordcount;
    /* grab columnlist */
    var columnlist = my_data.columnlist;
    /* grab json data */
    var json_data = my_data.data;

    /* PUTS JSON DATA INTO ARRAYS */
    for(var x = 0; x < recordcount; x++) {
        var lng = json_data.lng[x];
        var phrase = json_data.phrase[x];

        if (lng == 'french') {

            fr_lang[fr_count] = phrase;
            fr_count = fr_count + 1;
        }
        if (lng == 'french canadian') {

            frca_lang[frca_count] = phrase;
            frca_count = frca_count + 1;
        }
        if (lng == 'english') {

            en_lang[en_count] = phrase;
            en_count = en_count + 1;
        }
    }

    /* use a replacetext function above to replace all text */ 

    for(var x = 0; x < en_lang.length; x++) {
      var from = en_lang[x];
      if (language == 'fr') {  
        var to = fr_lang[x];
      }
      if (language == 'frca') {  
        var to = frca_lang[x];
      }
      replaceText(from, to);
    }



}

Извините, не совсем уверен, как получить код публикации, правильно отформатированный, не стесняйтесь редактировать мой пост в этой ситуации ..

Спасибо.

Ответы [ 3 ]

2 голосов
/ 01 февраля 2010

Изучив ваш код, я могу вам сказать, что ваша самая большая нагрузка создается в функции replaceText. Для каждого текстового элемента ваш код проходит снова и снова через всю структуру DOM. Вместо того, чтобы делать это за один раз, код проходит документ en_lang.length раз. Манипулирование узлами намного медленнее, чем в коде JavaScript, поэтому, если у вас много элементов в массиве en_lang и структура документа сложна, время рендеринга может резко возрасти. Выполнение замены всех текстовых элементов в одном цикле сэкономит много времени.

Во-вторых. Я вижу, что на каждом узле вы выполняете операцию присваивания. node.textContent = node.textContent.replace(oldText, newText); Эта операция излишня, если ваш узел не содержит никакой информации о совпадении. Выполняя назначение DOM только там, где это необходимо, вы экономите себе еще одну мс времени рендеринга.

В-третьих. Рекурсия. Действительно интересная тема. Можно использовать, можно не использовать. Что ты предпочитаешь. Но иногда рекурсия может быть узким местом в коде. В этой ситуации replaceText является операцией повторного запуска, которая приводит к ненужному использованию памяти и времени процессора. Вы можете получить все узлы за один шаг, задав для этого функцию getElementsByTagName.

Четвертый: операции "if" внутри "parseJson" в первом цикле for. Я не знаю почему, но вы не используете операторы if-else, а просто if. Это означает, что во время выполнения должны пройти все операторы «если», даже если он уже нашел правильный. В этом случае для эффективности JavaScript лучше использовать оператор «switch» вместо «if» или «if-else». Это быстрее.

Пятый. Давайте посмотрим теперь во втором цикле «для». Вы не должны использовать там любой переключатель или оператор if вообще. Утверждения «если» в этой части полностью излишни. Вы знаете значение вашей «языковой» переменной перед циклом for, поэтому вы можете кэшировать массив «to» перед циклом for и использовать уже кэшированный массив.

Шесть: еще одно небольшое улучшение вместо использования frca_count = frca_count + 1; Вы можете просто использовать инкрементальный оператор: frca_count ++. Это также ускорит код.

Seven. Во втором операторе for: вы используете en_lang.length в условной части. Если вы посмотрите на предыдущий цикл for, вы увидите, что в нем есть переменная с тем же значением: en_count. Используйте ее вместо en_lang. длина для ускорения самой петли.

Объединяя все это вместе, я придумал что-то вроде этого.

function parsejSON(my_data) {
 /* THIS PART GRABS DATA FROM TOP OF JSON FILE */

 /* grab recordcount */
 var recordcount = my_data.recordcount;
 /* grab columnlist */
 var columnlist  = my_data.columnlist;
 /* grab json data */
 var json_data   = my_data.data;

 /* PUTS JSON DATA INTO ARRAYS */
 for(var x = 0; x < recordcount; x++) {
  var lng    = json_data.lng[x];
  var phrase = json_data.phrase[x];

 // ( conclusion # 4)
  switch(lng){
   case 'french':
    // ( conclusion # 6)
    fr_lang[fr_count++] = phrase;
    break;
   case 'french canadian':
    frca_lang[frca_count++] = phrase;
    break;
   case 'english':
    en_lang[en_count++] = phrase;
    break;
  }
 }

 /* use a replacetext function above to replace all text */ 
 // ( conclusion # 5)
 var toCache = (language == 'fr') ? fr_lang 
 : (language  == 'frca' ? frca_lang : null);


 // ( conclusion # x)
 var content = function(node, txt){
  if(txt){
   if(node.textContent){
    node.textContent = txt;
   }else if(node.nodeValue){
    node.nodeValue = txt;
   }
  }else{
   return node.textContent ? node.textContent : node.nodeValue;
  }
 };

 // recursive tree walker
 (function(parent){
     var childs = parent.childNodes;
     if(childs && childs.length){
         for(var i=0,node;node = childs[i];i++){
             if(node.nodeType == 3){ // text node found, do the replacement
                 var value  = content(node);
                 // ( conclusion # 7)
                 for(var x = 0; x < en_count; x++) {
                     var from = en_lang[x];
                     var to   = toCache[x];
                     // ( conclusion # 2)
                    if(value.match(from)){
                        content(node, value.replace(from,to));
                    }
                 }
             }else{
                 arguments.callee(node);
             }
         }
     }
 })(document.body);
* *} Тысяча двадцать-один

Надеюсь, все это должно сработать. Удачи

РЕДАКТИРОВАНИЕ: Поскольку getElementsByTagName ("*") не возвращает узлы #text, я изменил решение для использования рекурсивного обходчика деревьев.

0 голосов
/ 02 февраля 2010

Я бы посоветовал поместить каждый локализованный параметр в тег span, чтобы потом вы могли выбирать и обновлять свои параметры немного проще. Имея имя класса .localize, все вместе с именем класса .l-PARMNAME будут иметь достаточно узкий выбор для этого.

например: <span class="localize l-PARMNAME">English Value</span>

тогда вы можете иметь свои данные с ...

jsonData: { //note: this can come back from your ajax call
  language:'fr', 
  parms: { 
    "PARMNAME": "parm value",
    "OTHERPARM": "other value",
    ...
  }
}


$.each(jsonData.parms, function(key, value){
  ($('span.localize.l-'+key).text(value);
});

Приведенный выше код должен работать немного быстрее (с использованием jquery) в более новых браузерах, которые имеют лучшую модель выбора. Это должно работать нормально почти в любом браузере. Если производительность по-прежнему остается проблемой, вы можете выполнить цикл через $ ("span.localize"). Each () и проверить соответствующий подтег.

В противном случае вы можете просто зациклить свою английскую версию, но я бы предложил использовать тег span для каждого реплицируемого узла. даже просто селектор span.localize даст вам меньший узел, вы можете сравнить значение .text () и сопоставить / заменить всю строку ... использование .replace для строки в текстовом узле довольно тяжелый, поскольку вы должны получить значение текста, сопоставить строку (на основе регулярных выражений), а затем ввести новое значение в текстовый узел. возможность иметь узкий селектор тегов и возможность целевого выбора нужного узла будет работать с улучшенным поиском в новых браузерах.

0 голосов
/ 28 января 2010

Вы можете попробовать console.time в firebug. Это скажет вам, сколько времени вы экономите, когда вносите изменения. Это также поможет вам определить, какая из функций выполняется дольше всего (так что вы можете сначала оптимизировать их).

Как измерить время, затраченное функцией на выполнение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...