помогите соптимизировать алгоритм для 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, время: 15:09. |