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 строк

☆

Последнее исправление: anonimous (всего исправлений: 4)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

anonimous ☆
() автор топика

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

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

Я пробовал

код остался? давай если есть

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

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

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

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

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

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

а килялка (и решедуллинг) если новый символ пришел раньше начала поиска была?

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

понял что я написал и зачем это нужно?

ZuBB ★★★★★
()
Последнее исправление: ZuBB (всего исправлений: 1)
Ответ на: комментарий от 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 ★★★★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.