помогите соптимизировать алгоритм для V8
Проблема наблюдается только на V8. На слабом железе при быстром вводе наблюдается зависание инпута. Буквы не печатаются, а потом выскакивают разом по нескольку штук. Также, когда несколько раз жмешь бекспейс. Мое предположение, изначально, было в том, что при вводе следующего символа продолжает выполняться цикл внутри функции search, отсюда и тормоза. Я добавил что-то типа прерывания, однако ситуация не изменилась. Помогите, пожалуйста.
search=function(pattern){ var out=[] var re=new RegExp(pattern, "i") var current_flag=window.flag for(var i=0; i<base.length; i++){ if(current_flag!==window.flag) return;//вот тут прерывание if(base[i].match(re)) { base[i]=base[i].replace(/((\d{4} \d{2}-\d{3})|(\d{4} \d{2}-\d{3} \d{1}-\d{2}-\d{2}))$/, "<b>$1</b>") out.push(base[i]) } } return out } firstSearch=function(){ d.innerHTML="" input.style.color=null var out=search(input.value) if(out.length<1) return secondSearch() var str=out.join("<br><br>") d.innerHTML=str } secondSearch=function(){ input.style.color="red" d.innerHTML="Нет результатов для <b>"+input.value+"</b>" } onload=firstSearch input.oninput=firstSearch input.focus() onkeydown=function(){input.focus(); window.flag=new Date().getTime()} UPD: d -- это див на странице input -- input на странице base -- массив ~900 строк UPD2: Вот возможная причина: Насколько я себе это представляю, js однопоточен, и когда я ввожу следующий символ в input, он не может сразу отреагировать, не дождавшись завершения предыдущего поиска. Чтобы прервать этот цикл, внутри search, я устанавливаю флаг на событие нажатия клавиши, если следующяя клавиша была нажата, условие выполняется и мы выходим из цикла на текущей итерации. Это было мое предположение, но не помогло. Похоже я лоханулся в том, что событие нажатия само по себе не может наступить, не дождавшись выполнения цикла, поэтому пока цикл не выполнится, прерывание лфаг не изменится, вот в чем ошибка наверное. Но как это фиксить -- хз |
Тут не нужна оптимизация под V8. Тут нужен жирный рефакторинг. Кроме того, ты приводишь только часть кода. Где объявлены d, input, base?
|
Цитата:
input -- input на странице base -- массив ~900 строк А при чем тут рефакторинг? |
При том, что самая лучшая оптимизация — смена подхода. Подожди полчасика, я запощу свой вариант, может он не будет тормозить.
|
Зачем, кстати, используются current_flag/window.flag?
|
Цитата:
Цитата:
|
В этом примере все продолжает тормозить? http://jsfiddle.net/ainop/g41x6tto/ Скинь куда-нибудь пример строк, которые ты используешь.
|
|
ixth,
Да, тормозит еще сильней пример строки ' Пупкина Светлана Николаевна товаровед (по многооборотной таре и обеспечению ж/д транспортом) 26 Отдел сбыта и транспортной логистики 5977 88-9595 5-40-20' |
Цитата:
|
ixth,
Так поменьше, но все равно тормозит. Думаю, на моих строках сильней оригинала будет тормозить. У меня есть тут одна мысля. Надо как то сделать, чтобы поиск начиналсмя с таймаутом, а в этом таймауте проверялось не изменился ли за это время инпут. Думаю, надо в этом направлении копать. Потом отпишусь. Пока не делай ничо, а то мне жалко твоего времени:), если не получится, тогда будем продолжать:) |
Ты не поверишь… Мой вариант почти так и делает. Он ждет, когда пользователь закончит ввод и только тогда запускает поиск. Плюс, тебе же не критично, что поиск ведется регуляркой? Можно заменить его на indexOf: http://jsfiddle.net/ainop/g41x6tto/4/
Больше никаких оптимизаций сделать, наверное, нельзя. Я бы перенес все это на сторону сервера и делал запросы через ajax. |
ixth,
Я изменил search вот так search=function(the_value){ var test=function(){return input.value==the_value} var out=[] var re=new RegExp(the_value, "i") for(var i=0; i<base.length; i++){ if(!test()) break; if(base[i].match(re)) { base[i]=base[i].replace(/((\d{4} \d{2}-\d{3})|(\d{4} \d{2}-\d{3} \d{1}-\d{2}-\d{2}))$/, "<b>$1</b>") out.push(base[i]) } } return out } И один хрен тормозит. Во всех остальных браузерах летает. Может это просто V8 кривой? Или я фигню написал? |
А если данных будет в 100 раз больше?
не возникает ощущение что задачу решаете не совсем правильно? |
MallSerg,
Я бы с удовольствием выслушал ваши предложения. |
Задача не озвучена полностью тут только весьма странная часть решения неизвестной задачи ((.
Возможно стоит задача поиска совпадений в текстовых строках. Со стороны задача выглядит как забивание саморезов в бетонную стену с помощью булки хлеба. )) |
MallSerg,
Задача - банальный поиск выборки по массиву с последующим выводом результата. |
Цитата:
как вообще могло прийти в голову выводить результат из 900 строк на каждое нажатие клавиши? На ладно давай допустим что есть люди читающие по 500 - 600 строк в секунду зачем использовать регулярные выражения для простого поиска чем не устраивает valueOF ? Почему функция называется поиск а на самом деле она генерит HTML ? Цитата:
|
MallSerg,
Вы господин, какую то феерическую ахинею несете. Или вникни в код наконец, или расслабься и отдохни. |
Цитата:
|
ixth,
он чушь несет несусветную, там перерисовка идет только один раз, после цикла, все браузеры все перерисовывают одинаково, иначе как юзер смог бы увидеть результаты поиска? Глупо было бы. |
Да, но "после цикла" раньше вызывалось при каждом нажатии на клавишу. Думаю, он про это.
|
Да, может и про это, и это тоже чушь. Браузер не может заранее знать, в какой момент будет нажата следующая клавиша, и будет ли нажата. Может быть там установлены таймауты минммальные, но это не принципиально. Визуально не видно никаких задержек, все выводится моментально.
|
ixth,
Проблема там не в выводе результатов, а в том, что во время выполнения цикла пользовательский ввод не может попасть в инпут, он ждет окончания цикла. |
ixth,
Да, кстати, я там заметил, что ты в своем коде используешь map для массива, типа, декларативное рулит, да, но это еще дополнительные тормоза+утечки памяти, возможно. Не надо так делать. Я вот тут протестил немножко test=function(f, i){ console.time(f.name) while(i--){f()} console.timeEnd(f.name) } mymap=function(arr, f){ var newArr=[] for(var i=0; i<arr.length; i++){ newArr[i]=f(arr[i]) } return newArr } mymappush=function(arr, f){ var newArr=[] for(var i=0; i<arr.length; i++){ newArr.push(f(arr[i])) } return newArr } thismap=function(f){ var newArr=[] for(var i=0; i<this.length; i++){ newArr[i]=f(this[i]) } return newArr } thismappush=function(f){ var newArr=[] for(var i=0; i<this.length; i++){ newArr.push(f(this[i])) } return newArr } arr=[0,1,2,3,4,5,6,7,8,9] f=function(x){return x} arr.thismap=thismap arr.thismappush=thismappush function tst_mymap(){ mymap(arr, f) } function tst_mymappush(){ mymappush(arr, f) } function tst_thismap(){ arr.thismap(f) } function tst_thismappush(){ arr.thismappush(f) } function tst_native_map(){ arr.map(f) } i=100000 test_=function(f){return test(f, i)} test_(tst_mymap) test_(tst_mymappush) test_(tst_thismap) test_(tst_thismappush) test_(tst_native_map) //tst_mymap: 77ms //tst_mymappush: 38ms //tst_thismap: 75ms //tst_thismappush: 81ms //tst_native_map: 301ms Тестил только на ноде, но результат как бы намекает. Врядли оно хот где-то быстрей будет. ЗЫ к моему удивлению, в старой опере действительно быстрей Started: tst_mymap tst_mymap: 7363ms (7362900µsec) Started: tst_mymappush tst_mymappush: 8298ms (8298206µsec) Started: tst_thismap tst_thismap: 6963ms (6963449µsec) Started: tst_thismappush tst_thismappush: 8201ms (8200867µsec) Started: tst_native_map tst_native_map: 5507ms (5506914µsec) Но в хроме: tst_mymap: 32.000ms tst_mymappush: 29.000ms tst_thismap: 31.000ms tst_thismappush: 27.000ms tst_native_map: 460.000ms В фф [11:55:18.280] tst_mymap: таймер запущен [11:55:18.420] tst_mymap: 140мс [11:55:18.420] tst_mymappush: таймер запущен [11:55:18.562] tst_mymappush: 142мс [11:55:18.562] tst_thismap: таймер запущен [11:55:18.711] tst_thismap: 149мс [11:55:18.712] tst_thismappush: таймер запущен [11:55:18.872] tst_thismappush: 160мс [11:55:18.873] tst_native_map: таймер запущен [11:55:19.166] tst_native_map: 293мс |
Проблема в выводе результатов
как следствие этой проблемы - пользовательский ввод ждет окончания вывода результатов. |
Каким образом map ведет к утечке памяти? И если придираться к мелочам, то почему ты так странно объявляешь функции?
|
MallSerg,
Возможно ты прав, извиняюсь что нагрубил, я в шоке. :) Я сгенерил массив в несколько тысяч строк, и поставил таймеры. Цикл выполняется 1-3 миллисекунды, основное время занимает отрисовка. Это если верить отладчикам. А я им не верю. Как такое может быть? Просто, видимо выполнение цикла не учитывается толком. Буду дальше эксперементировать. |
Цитата:
>> Цитата:
|
Цитата:
Но да, он медленнее. Т.к. у тебя критичное к скорости место, можешь заменить на for, ничего не имею против, просто мне было удобнее написать с мапом. Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 11:20. |