LINUX.ORG.RU

Народ, помогите в оптимизации JavaScript (userscript)


0

2

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

// ==UserScript==
// @name           test
// @namespace      test
// @include        http://www.linux.org.ru/*
// ==/UserScript==
// @author radiofun@jabber.org

function Smiles() {
 
  var smilesSrc = {
    "personal/angel.gif":"O:-) O:) O+) O=) 0:-) 0:) 0+) 0=) (A) (a)",
    "icq/smile.gif":":-) :) +) =) :smile:",
    "standart/sad.gif":":-( :( +( =( :-(( :(( +(( =(( :sad:",
    "icq/wink.gif":";-) ;) ^_~ :wink:",
    "standart/blum3.gif":":-P :P :-p :p +P =P +p =p :-b :b +b =b :tongue:",
    "standart/dirol.gif":"8-) 8) B) :COOL: :cool: COOL cool COOL! COOL!! COOL!!!",
    "icq/biggrin.gif":":-D :D +D =D :biggrin:",
    "standart/blush2.gif":":-[ :[ ;'> ;-. :blush:",
    "remake/shok.gif":"=-O =O =-o =0 O_O O_o o_O O_0 o_0 0_O 0_o",
    "icq/kiss.gif":":-* :* :-{} :{} +{} ={} ^.^ :kiss: *KISS*",
    "standart/cray2.gif":":'( :'-(",
    "standart/secret.gif":":-X :-x X: x: :-# :# :secret:",
    "standart/aggressive.gif":">:o >:O >+O >:o >+o :-@ :angry:",
    "standart/fool.gif":":-| :| =|",
    "standart/beee.gif":":-\\ :-/ :\\",
    "standart/mosking.gif":"*JOKINGLY* 8P 8p",
    "personal/diablo.gif":"]:-> }:-> ]:> }:> >:-] >:] (6) :diablo: *DIABLO*",
    "personal/music2.gif":"[:-} [:}",
    "standart/air_kiss.gif":"*KISSED*",
    "standart/bad.gif":":-! :! :-~ ;-~ :(~ +(~ =(~ :bad:",
    "standart/boredom.gif":"*TIRED* |-0 :boredom:",
    "standart/stop.gif":"*STOP* STOP STOP! STOP!! STOP!!! :stop:",
    "icq/give_rose.gif":"@}->-- @}-:-- @>}--,-`--- (F) (f)",
    "standart/good.gif":"*THUMBS_UP* :GOOD: :good: GOOD! *GOOD*",
    "standart/drinks.gif":"*DRINK* DRINK :drink:",
    "madhouse/man_in_love.gif":"*IN_LOVE* LOVE",
    "other/bomb.gif":"@=",
    "madhouse/wacko.gif":"%) %-) :-$ :$ :wacko: :WACKO:",
    "personal/mamba.gif":"*WASSUP* *SUP* *MAMBA* :MAMBA:",
    "standart/clapping.gif":"*BRAVO* :BRAVO: :bravo: :clapping:",
    "icq/rofl.gif":"*ROFL* :ROFL: :rofl: ROFL ROFL! rofl :-)))) :-))))) :-)))))) :)))) :))))) :)))))) =)))) =))))) =))))))",
    "standart/pardon.gif":"*PARDON* =] :PARDON: :pardon: PARDON",
    "standart/nea.gif":"*NO*",
    "icq/crazy.gif":"*CRAZY* :crazy:",
    "standart/dntknw.gif":"*DONT_KNOW* *UNKNOWN* :HZ: :hz:",
    "standart/sorry2.gif":"*SORRY* :sorry:",
    "standart/yahoo.gif":"*YAHOO* *YAHOO!* :YAHOO: :yahoo: YAHOO! Yahoo! YAHOO!! Yahoo!! YAHOO!!! Yahoo!!!",
    "standart/dance4.gif":"*DANCE* :dance:",
    "standart/help.gif":"*HELP*",
    "standart/ok.gif":"*OK*",
    "personal/new_russian.gif":"\\m/ \\M/"
  };

  var bor;

  function addToBor(smiles, file) {
    var node = bor;
    var nnode = null;//next node
    var s = 0;
    for(var i = 0; i < smiles.length; ++i) {
      var smile = smiles[i];
      for(var j = 0; j < smile.length; ++j) {
        var c = smile.charAt(j);
        nnode = node[c];
        if(!nnode) {
          node[c] = nnode = {};
        }
        node = nnode;
      }
      node.end = {
        file: file, 
        smile: smile, 
        len: smile.length
      };
      node = bor;//возвращаемся к корню  
    }
  } 

  //добавление переходов "неудачи"
  function findAndAddAlternatives(srcNode, stack) {
    for(var i = 1; i < stack.length; ++i) {
      var c;
      var destNode = bor[c = stack[i]];
      for(var j = i + 1; destNode && j < stack.length; ++j) {
        destNode = destNode[c = stack[j]];
      }
      if(destNode) {
        for(var destC in destNode) {
          if(!srcNode[destC]) {
            srcNode[destC] = destNode[destC];
          }
        }
      }
    }
  }
  
  function visitor(node, stack) {
    for(var i in node) {
      var child = node[i];
      if(!child.end) {
        var childStack = stack.concat(i);
        visitor(child, childStack);
        findAndAddAlternatives(child, childStack);
      }
    }
  }

  function createBor() {
    if(!bor) {
      bor = {};
      for(var file in smilesSrc) {
        var smiles = smilesSrc[file].split(" ");
        addToBor(smiles, file);
      }
      
      node = bor;
      var stack = [];
      visitor(node, stack);
    }    
  }


  //replacing

  this.replace = function(node) {
    createBor();
    if(node.nodeType == 3 /* Node.TEXT_NODE*/) {
      var str = node.nodeValue;
      var parsed = [];
      var borNode = bor;
      var last = null;
      for(var i = 0; i < str.length; ++i) {
        var c = str.charAt(i);
        borNode = borNode[c];
        if(!borNode) {
          borNode = bor;
          if(last) {
            parsed.push(last);
            last = null;
          }
        } else if(borNode.end) {
          var e = borNode.end;
          if(!last || (last.s >= i - e.len && last.e <= i)) {
            last = {
              s: i - e.len + 1,
              e: i,
              n: e, 
              file: e.file
            };
          }
        }
      }
      //замена
      var parent = node.parentNode;
      for(var i = parsed.length - 1; i >= 0 ; --i) {
        var p = parsed[i];
        var text = node.splitText(p.s);
        text.deleteData(0, p.n.len + 1);
        var img = document.createElement("img");
        img.src = "http://www.kolobok.us/smiles/" + p.file;
        parent.insertBefore(img, text);
      }
    }
    if(node.childNodes) {
      for(var i = 0 ; i < node.childNodes.length; ++i) {
        this.replace(node.childNodes[i]);
      }
    }  
  }
}


/*
this.createMenu = function(handler) {
  var menu = document.createElement("div");
  for(var s in smiles) {
    var se = document.createElement("img");
    se.src = site + smiles[s];
    se.addEventListener("click", (function(s){
      return function(){handler(s)};
    })(s), false);
    menu.appendChild(se);
  }
  return menu;
}*/
//window.onload = function() {
  try{
    var smiles = new Smiles();

    var i = document.evaluate("//div[1]/div[@id='bd']/div[@class='messages']/div[@class='comment']/div/div[3]", document, null, XPathResult.ANY_TYPE, null);
    var c;
    var comments = []
    while(c = i.iterateNext()) {
      comments.push(c);
    }
    
    for(var j = 0; j < comments.length; ++j) {
      var comment = comments[j];
      smiles.replace(comment);
    }
    /*var msg = document.getElementById("msg");
    var menu = smiles.createMenu(function(smile) {
      var val = msg.value;
      var s = msg.selectionStart;
      var e = msg.selectionEnd;
      msg.value = val.substring(0, s) + smile + val.substring(s, val.length);
    });
    msg.parentNode.insertBefore(menu, msg);*/
  } catch(e) {
//    console.error(e);
  }
//}


И еще подскажите как выключить обработку строки с датой у каждого поста, а то когда там попадается 18) то получается смайлик. Или сделать отбивку пробелами?

kifer ()
Ответ на: комментарий от kifer

А еще /development/ станет смищной-смищной.

anonymous ()
Ответ на: комментарий от derlafff

Видишь ли, там смайлики нужно было отбивать *-кой и т ребовался jquery, выфер пообещал исправить, но его забанили. Так что он попросил меня запостить это тут. Это раз.

Кроме того отбивать самйлики *-ками нельзя ибо Common Sense запрещает портить читабельность постов, потому потребовался другой алгоритм поиска, чем выфер и занимался неделю.

kifer ()
Ответ на: комментарий от Deleted

это нарушит дизайн класса smiles, который можно юзать на любом сайте в принципе.

kifer ()

Для простых смайлов это какой то сложный скрипт. Побуквенные деревья смайлов. Сделай проще.

var t = v.data, 
  t2 = t.replace(
    /:\)|:\(... /g /* рега со всеми смайлами */,
    function(smile)
    {
      return '<img src="' + smileToFileMap[smile] + '">'; 
    } 
  )
; 

if(t2 != t) /* тут меняем текстовую ноду на span с innerHTML = t2 */
что то внутри меня подсказывает что версия на регах будет быстрее твоих деревьев

bga_ ★★★ ()
Ответ на: комментарий от bga_

+1
тоже думаю, что нужно работать с сообщением как с целиковым текстовым блоком, побыстрее будет.

avol ()
Ответ на: комментарий от bga_

что то внутри тебя должно подсказать тебе написать тестик и убедиться

kifer ()
Ответ на: комментарий от kifer

> а я гдето сказал что не хочу?
Ну

Или сделать отбивку пробелами?

вроде подразумевает, не?

режекспы подмесят тормозов

Может быть, но технология неплохо оптимизированная, иногда разница может быть несущественной…

avol ()
Ответ на: комментарий от avol

>вроде подразумевает, не?

Блин, в школе уже не учат распознавать вопросительные предложения, чтож тебе порекомендовать то?

Может быть, но технология неплохо оптимизированная, иногда разница может быть несущественной…

Не надо мне байки про оптимизированные тухнологии. Есть алгоритм поиска подстроки, есть алгоритм поиска подстрок Ахо-Корасик кой с 70х годов особо не оптимизирвоали, в сабже юзается его урезанная версия.

Так шо тут ты можешь что то доказать только тестами, и то это придется проверять в каждом бравзере.

kifer ()
Ответ на: комментарий от kifer

> Блин, в школе уже не учат распознавать вопросительные предложения, чтож тебе порекомендовать то?

Объясняю — предложение «Или сделать отбивку пробелами?» ставит вопрос «сделать её, или нет». Я на него отвечаю рекомендацией не делать, а использовать определение границы слова. Теперь ок, распарсил?

Так шо тут ты можешь что то доказать только тестами, и то это придется проверять в каждом бравзере.


Да хорошо, не волнуйся ты так — используй обход дерева. Просто сам ведь ищешь способы оптимизации, вот и озаботься тестами. А коль не хочешь — ну и не надо.
Только вот издревле смайлы регэкспами вставляли, ну да ладно — белк умнее всех, мы верим в торжество великого разума и всё такое…

avol ()
Ответ на: комментарий от avol

>Объясняю — предложение «Или сделать отбивку пробелами?»

Почему мне попадаются люди с короткой памятью:

если ты не хочет делать отбивку

про границы слова лучше сделай тест если умыслить какой это писец по производительности будет не можешь.

Просто сам ведь ищешь способы оптимизации, вот и озаботься тестами.

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

kifer ()

Итак, переделав цикл поиска в функции replace

как указано ниже, мы избегаем сравнения каждого символа в тексте, и получаем отбивку пробелами.

for(var i = 0; i < str.length; ++i) {
        if(i > 0) {
          i = str.indexOf(' ', i);
          if(i < 0) {
            break;
          }
          ++i;
        }
        for(var j = i; j < str.length; ++j) {
          var c = str.charAt(j);
          borNode = borNode[c];
          if(!borNode) {
            borNode = bor;
            if(last) {
              parsed.push(last);
              last = null;
            }
            break;
          } else if(borNode.end) {
            var e = borNode.end;
            if(!last || (last.s >= i && last.e <= j)) {
              last = {
                s: i,
                e: j,
                n: e, 
                file: e.file
              };
            }
          }
        }
      }

и в итоге не будет подсвеичиваться 18), но будет 8),

kifer ()

Такие посты - неуважение, имхо. Автор рассчитывает, что люди на его задачу потратят время, но сам пожалел времени почистить из кода камменты и лишние смайлы (2-3 строчек со смайлами было бы достаточно, чтоб понять суть). В результате получился длинный унылый пост.

Представляю, как разработчик ядра пишет пост: «помогите оптимизировать код: » - и дальше весь исходник ядра.

heisenberg ★★ ()
Ответ на: комментарий от kifer

> Почему мне попадаются люди с короткой памятью:

Почему мне попадаются белки с коротким мозгом? Может потому, что у них у всех он короткий?

про границы слова лучше сделай тест если умыслить какой это писец по производительности будет не можешь.


Я достаточно много чего делал на регекспах, в том числе и весьма сложного разбора. Я вполне неплохо представляю какого объёма должен быть текст, чтобы вызвать ощутимые тормоза.

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


Мой сладенький, вопрос в поиске оптимальных решений твой, проблема твоя — вот и устраивай тесты, тебе же это нужно. Я лишь высказал один из возможных вариантов реализации.

avol ()
Ответ на: комментарий от Vit

1) что хотеть от пхепе кодера, конечно ему пристало решать режекспами монструозные задачи

2) пехепекодеры не видят разлчиям между любимым пехепе и жабаскриптом

kifer ()
Ответ на: комментарий от kifer

Браза, у меня все работает хорошо и быстро. А про медленный говнокод и глупости про регекспы спрашивает кое-кто другой.

Vit ★★★★★ ()
Ответ на: комментарий от Vit

>у меня все работает хорошо и быстро

Субъективизм.

про медленный говнокод и глупости про регекспы спрашивает кое-кто другой.

Про говнокод во всем треде твой пост самый первый, так что дела выводы. А про режекспы, я тебе предложил ткнуть меня лицом в грязь тестами, но так как их все еще никто не опубликовал, то видимо им стыдно.

kifer ()
Ответ на: комментарий от kifer

Как истинные джентльмены, они ждут новых откровений, почему насчет ВАШИХ проблем надо что-то доказывать.

Если будут свежие мысли, как называть ммм... чуднокод, где 90% делает ненужную оптимизацию, тоже обязательно расскажите.

Vit ★★★★★ ()
Ответ на: комментарий от Vit

Я вам рожу хоть десяток неологизмов, как вы докажете ненужность оптимизации тестами, ок? А метанировать может всякий.

kifer ()
Ответ на: комментарий от kifer

Пока тут метанирует только 1 белка, которой 3 человека с реальным опытом сказали, что «самопальные регекспы» того не стоят.

http://habrahabr.ru/blogs/sphinx/109667/ Гиг с лишним там парсился 130 секунд. Если с мозгом проблем нет - сможете построить аналогии с жабаскриптом и понять, почему в вашем случае экономить на регекспах смысла нет.

Vit ★★★★★ ()
Ответ на: комментарий от Vit

> Это не компилируемый код. Регекспами будет проще и быстрее.

Таки да. При сколько-нибудь сложных условиях, регулярки будут быстрее.

JustGuest ()

А по существу, работа с DOM (особенно перерисовка страницы) занимает намного больше времени (два-три порядка), чем операции собственно языка.

Можно попробовать вставлять ноды с классом для которого стоит display:none и в конце убрать этот класс/стиль.
Но предварительно следовало бы измерить, как долго выполняются отдельные куски кода.

JustGuest ()
Ответ на: комментарий от JustGuest

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

kifer ()
Ответ на: комментарий от JustGuest

Вот, кто то начал догадываться о сути вещей, только display:none не сильно спасет, тормоза начинаются когда браузер подгружает смайлики если их много. А если мало и много текста то split - тормоза дает.

kifer ()
Ответ на: комментарий от kifer

Увы, пока я тут вижу только дефект мозга, не позволяющий интерпретировать результаты тестов, да.

Vit ★★★★★ ()
Ответ на: комментарий от kifer

Слишком сильное утверждение. Да, простой поиск строки слегка быстрее регулярки («a.indexOf('abc') == -1» - 123мс, «/abc/.test(a)» - 137мс), но стоит усложнить условия и ситуация вполне может измениться: «/abc/i.test(a)» - 141мс, «a.toLowerCase().indexOf('abc') != -1» - 251мс.

Да и упираться в поиск, в реальных условиях, оно почти никогда не будет.


str.charAt(j)


Кстати, это почти вдвое медленнее, чем str[j] :)

JustGuest ()
Ответ на: комментарий от JustGuest

Слишком сильное утверждение. Да, простой поиск строки слегка быстрее регулярки

не слегка, у тебя другой бравзер видать. И для текущей задачи простой поиск не подходит, сабжевый метод адаптация ахо-корасик, на браузерах без предкомпиляции скриптов теоретически может сливать режекспам, с предкомпиляцией - уже не может даже теоретически.

ar a = 'abc';if(/abc/.exec(a)[1]){} else {}	1443
var a = 'abc';if(a.match(/abc/)){} else {}	357
var a = 'abc';if(a.search(/abc/) == -1){} else {}	362
var a = 'abc';if(/abc/.test(a)){} else {}	340
var a = 'abc';if(a.indexOf('abc') + 1){} else {}	163
var a = 'abc';if(a.indexOf('abc') == -1){} else {}	155
var a = 'abc', h = {abc:1};if(h[a]){} else {}	106
var a = 'abc';if(a === 'abc'){} else {}	74

Кстати, это почти вдвое медленнее, чем str[j]

Ибо non standart

kifer ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.