LINUX.ORG.RU

Помогите соптимизировать алгоритм для V8

 ,


0

3

Проблема наблюдается только на V8. На слабом железе при быстром вводе наблюдается зависание инпута. Буквы не печатаются, а потом выскакивают разом по нескольку штук. Также, когда несколько раз жмешь бекспейс. Мое предположение, изначально, было в том, что при вводе следующего символа продолжает выполняться цикл внутри функции search, отсюда и тормоза. Я добавил что-то типа прерывания, однако ситуация не изменилась. Помогите, пожалуйста.

UPD2:

Вот возможная причина: Насколько я себе это представляю, js однопоточен, и когда я ввожу следующий символ в input, он не может сразу отреагировать, не дождавшись завершения предыдущего поиска. Чтобы прервать этот цикл, внутри 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 строк

900 строчек это не так много даже для самого захудалого компа.

Я добавил что-то типа прерывания

оно не работает. попытайся понять почему

основной хинт: поиск нужно стартовать после некоторого интервала после того как юзер перестал жать клавиши

мелкие хинты: вместо «match» использовать «test»; регексп для «replace» тоже единожды создать с помощью «new RegExp»; «onkeydown» заменить на «onkeyup»

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

событие нажатия клавиши не наступит пока цикл не закончится?

вообщето это правильное утверждение, но не это причина ошибки

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

основной хинт: поиск нужно стартовать после некоторого интервала после того как юзер перестал жать клавиши

Я пробовал, но это только косметика, после того, как наступит время интервала, после начала цикла управление все равно не передается в oninput, похоже.

anonimous ()

насчет «upd2» — мыслишь в правильном направлении

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

но не это причина ошибки

Ну как не это? Основная цель — прервать цикл. Цикл не прерывается, воответственно онинпут не наступает вовремя, отсюда и тормоза при вводе.

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

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

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

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

anonimous ()

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

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

Минимальный таймаут 0. Выполнение будет медленным. Можешь отдавать управление не каждую итерацию, а каждые 0.1 с например или по-другому группировать. В любом случае это баланс между throughtput и latency.

Ещё можешь почитать про web workers, не знаю, насколько они поддерживаются сейчас.

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

Почему плохо? Пока пользователь быстро печатает, ему подсказки не нужны. Если остановился, через полсекунды показать — нормально. Таймаут 0 значит, что функция будет выполнена сразу же после того, как будут обработаны все события, которые висят в очереди.

Legioner ★★★★★ ()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от Legioner

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

при 0 функция будет выполнена каждый раз после возникновения нового события. тоесть +- то что и происходит сейчас

а нужно добится такого поведения

нажали клавишу -> шедулинг поиска -> естевстенная пауза -> [[нажали клавишу -> затерминейтили предыдущий шедулинг и сделади новый -> естевстенная? пауза]...] -> шедуллинг отработал, запустился поиск

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

Я подумал, грешным делом, сделать по твоему совету, почти, но через break.


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 кривой сам по себе, он ложит на эти инструкции Х. Во всех остальных браузерах все летает. Даже безо всяких оптимизаций все норм было.

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

Пока ты не отдашь управление из твоей функции, браузер не обработает события с мыши и клавиатуры и не обновит значение input.value. Однопоточный JS-движок значит ровно то, что в браузере один поток на всё. И пока ты его держишь своим кодом, ничего в нём не будет происходить. Тебе надо периодически отдавать управление браузеру, чтобы он разгрёб очередь входящих сообщений и обновил интересующие тебя поля.

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

при 0 функция будет выполнена каждый раз после возникновения нового события. тоесть +- то что и происходит сейчас

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

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

да, Вы правы. я не правильно интерпретировал ваше предыдущее сообщение

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