Google Suggest – взгляд изнутри…

Original author: Chris Justus
  • Translation
Разные люди немного разбирались в принципе работы Google Suggest, но я переписал сжатый javascript код так, чтобы каждый обычный разработчик мог подробно узнать, как эта система работает. Моя финальная переписанная версия скрипта доступна здесь.
Я увидел самую крутую штуку, которую я видел с тех пор как обнаружил SOAP-клиент с поддержкой WSDL в браузере Mozilla. Технология предсказания запросов Google Suggest работает в реальном режиме времени. С вводом каждой новой буквы список вариантов обновляется. Скрипт технически восхитителен как минимум по двум причинам:

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

2. Интерфейс. Я пользовался в основном серверным кодом и старался избежать яваскрипта, но стал менять свое мнение о клиентских скриптах, пользуясь впечатляющими интерфейсами gmail, а теперь и google suggest (а также многими другими продуктами Google).

Думаю, что каждый может положительно оценить работу кода по следующим причинам:

1. Выпадающее меню идеально соответствует ширине поисковой строки…

2. Самый подходящий вариант в строке поиска выделен.

3. Отлично реализовано слежение за нажатиями клавиш и положением курсора мыши.

4. Отличная поддержка кэша, так что после нажатия Backspace скрипт не посылает новый запрос на сервер.

5. Динамическая подстройка скорости обновления в зависимости от пинга на Google.

Итак, мне захотелось понять динамический интерфейс этой разработки.
Я сохранил html и javascript локально… Я запустил его и использовал отладку для «расшифровки» обфусцированного скрипта.
Объект XMLHTTP / XMLHttpRequest служит для коммуникации с сервером Google, отправки запросов и получения данных без обновления страницы… Чтобы полность понять код, мне было необходимо знать, что присылает обратно сервер. Но когда я пытался открыть url напрямую, то не получал ничего, кроме 404 ошибки. Я пробовал использовать локальный прокси сервер для браузера, но выяснилось, что объект XMLHttp не использует браузерный прокси при соединении.
Оригинальный обфусцированный скипт Google доступен здесь

Выполнение скрипта вызывается из HTML-страницы командой InstallAC()…
Интересно, что при этом осуществляется проверка:
var Jb=«zh-CN|zh-TW|ja|ko|vi|»
То есть система пытается определить пользователей из Японии, Кореи и Китая, что может говорить о поддержке не только английского, но и азиатских языков.
Функция InstallAC вызывает другую функцию (installACPart2), которая проверяет поддержку браузером XMLHttp и создает ресурс «_completeDiv», куда и направляется контент, полученный с сервера.
Функция mainLoop вызывается периодически используя javascript функцию setTimeout. Интересно заметить, что разработчики решили использовать механизм, основанный на timeout, а не на keydown. Это было сделано для тех пользователей, которые имеют быструю скорость печати и медленное Интернет-соединение. Эта функция выясняет, изменилось ли значение текстового поля, а затем сначала ищет в закешированных данных, а затем отправляет новый запрос к серверу. Код google suggestion также поддерживает старые браузеры, не имеющие в ядре объект XMLHttp, использую технологию cookies и перезагружая фрейм.

Обычный запрос к серверу Google довольно прост. При обращении к серверу формируется строка www.google.com/complete/search?hl=en&js=true&qu=fast%20bug (для примера использована фраза «fast bug»).

Затем задается _xmlHttp.onchange колбэк-функция, которая получит данные запроса:

sendRPCDone(frameElement, «fast bug», new Array(«fast bug track», «fast bugs», «fast bug», «fast bugtrack»), new Array(«793,000 results», «2,040,000 results», «6,000,000 results», «7,910 results»), new Array(""));

Эта функция объявляется в файле ac.js. Она задает время основного цикла запроса, кэширует полученные результаты поиска и заполняет ими элемент _completeDiv DIV.
Функция displaySuggestedList отображает полученные результаты, создавая структуру данных из элементов DIV и SPAN. Для каждого элемента в полученном списке структура данных будет иметь следующий порядок:

<DIV (u) - mousedown/mouseover/mouseout class="aAutoComplete">
<SPAN (ka) class="lAutoComplete">
<SPAN (ua) class="cAutoComplete">
bug tracking
</SPAN (ua)>
<SPAN (ea) class="dAutoComplete">
500,000 results
</SPAN (ea)>

</DIV (u)>

Функция Pa() вызывается тогда, когда данные с сервера получены, а так же когда нажимается кнопка. Она подсвечивает введенный текст.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 30

  • UFO just landed and posted this here
      +6
      блин, все дружно любят таймауты, у меня firefox на лаптопе просыпается раз 200-300 в секунду если открыто несколько табов. Вроде бы не проблема, но современные процессоры думают иначе, когда их выдергивают из сна - итог батарейка садится на час раньше
        0
        с помощью флеша или JS можно отследить активно ли окно/вкладка и саспендить таймауты.
          0
          как?
            0
            http://vpleer.ru/index.php?q=snoop+dogg+…

            умеет понимать активна вкладка или нет. В случае если неактивна, он доигрывает песню и останавливается, как только переключаешься на нее, он продолжает играть. Я еще не разбирался в этом, но подозреваю, что это делает флеш.
              0
              точно не уверен, но по моему у окна есть методы blur() и focus(), соответственно должны быть и события onblur, onfocus.
    • UFO just landed and posted this here
        0
        спасибки
          +1
          >mainLoop вызывается рекурсивно используя javascript функцию setTimeout
          мда.. в код не смотрел, но что-то мне подсказывает, что автор хотел сказать переодически, а не рекурсивно.

          Два идущих подряд списка начинаются с практически одинаковых фраз: "восхитителен как минимум по двум причинам" и "восхититься работой кода по следующим причинам" - причём второй список "восхищений" покрывает первый, читается как-то не очень.

          Заметка интересна, но над стилем и содержанием надо было ещё поработать перед публикацией, куда торопиться, это же не горячая новость.
            +1
            А! это же перевод - не заметил сразу.
              0
              Спасибо за отзыв, изменения внесу.
                0
                Таки художественный перевод характерен тем, что текст адаптируют под языковые традиции. В английском повторения фраз возможны, а у нас считаются признаком плохого тона - почему бы и не убрать :)
            • UFO just landed and posted this here
                0
                обфускация
                  0
                  > обсфуцированный
                  обфусцированный
                    +1
                    в свое время это было безусловно круто, но, блин, статья 2004 года
                    сейчас это почти банальности
                      +1
                      да нас — да :) но не для тысяч начинающих JS-разработчиков :)
                      +2
                      А помоему, даже очень хорошо что всё так разжёванно подробно, просто, популярно.
                      • UFO just landed and posted this here
                          0
                          Супер! Настоящее расследование.
                            0
                            Спасибо за статью.
                            Кстати, до недавнего времени использовал jquery autocomplete.
                              0
                              а теперь что?
                              и чем автокомплит не устраивает больше?
                                0
                                А теперь попробую перейти на google suggest. Не хочу тянуть jquery ради одного элемента.
                              0
                              в избранное, однозначно
                                +4
                                Обязательно так засирать объект window?
                                Это что нельзя засунуть в какой-нибудь namespace?

                                var w="";
                                var pa=false;
                                var _oldInputFieldValue=""; // inputField value (set during call to google...)...(was ta)
                                var da=false;
                                var _currentInputFieldValue=""; // also inputField value (was g)
                                var G="";
                                var _eventKeycode=""; // event keycode... (was m)
                                var _highlightedSuggestionIndex=-1; // currently hightlighted suggestion index (was j)
                                var _highlightedSuggestionDiv=null; // currently highlisted suggestion div... (was h)
                                var _completeDivRows=-1; // completeDiv rows at time of keypress... (was Z)
                                var _completeDivDivList=null; // completeDiv div list at time of keypress (was za)
                                var _completeDivRows2=5; // was Ca... initially 5? not sure difference between this and _completeDivRows...
                                var q="";
                                var _divTag="div"; // Was Lb
                                var _spanTag="span"; // Was Bb
                                var _documentForm=null; // Form on html page... (was la...)
                                var _inputField=null; // Input field on form... (was a)
                                var _completeDiv=null; // document.completeDiv (was b)
                                var _submitButton=null; // submit button (was Xa)
                                var mb=null;
                                var X=null;
                                var _enString=null; // This becomes the string "en" (was ha)
                                var _cursorUpDownPressed=false; // Was ra...
                                var kc=null;
                                var hc=null;
                                var _resultCache=new Object(); // This is a cache of results from google... (was Ua)
                                var ca=1;
                                var Aa=1;
                                var Y=false;
                                var _lastKeyCode=-1; // Gets set on keyDown... Was na...
                                var Va=(new Date()).getTime();
                                var _hasXMLHTTP=false; // Gets set to true if XMLHTTP Supported (was Q)
                                var _xmlHttp=null; // This is the XMLHttp Object... (was k)
                                var _completeSearchEnString=null; // Gets set to "/complete/search/?hl=en" (was sa)
                                var _completeSearchString=null; // Gets set to "/complete/search" ... (was E)
                                var B=null;
                                var aa=null;
                                var Ba=false;
                                var Ka=false;
                                var p=60;
                                var _searchString=null; // Gets set to "search" in installAC (was ia)
                                var ya=null;
                                var _timeoutAdjustment=0; // timeout adjustment... (was W)... gets adjusted over time...
                                [имена функций перечислять не стал]

                                Полезность этих (и не только) переменных сложно недооценить:
                                var _divTag="div";
                                var _spanTag="span";

                                Стиль и подход коментировать лучше вообще не буду.
                                  0
                                  может у них обфускатор такой умный?
                                  а вообще, он выполняет свою работу, а это главное
                                    0
                                    1. Может у них обфускатор такой умный что...
                                    2. Конечно, естественно, однозначно. К тому же, кому ещё в объекте window могут понадобиться такие нелепые имена как: "_documentForm", "_xmlHttp", "w", "G", "q", "X", "Y", "B", "p",... э, а где остальные буквы, в алфавите их ещё много.
                                  +1
                                  на волшебном слове "хуй" suggest ломается и показывает слова начинающиеся на equ
                                    0
                                    думаю, что это работает фильтрация нецензурщины
                                    0
                                    Стиль написания скрипта адски-ужасен. Как-то все через задницу сделано...

                                    Only users with full accounts can post comments. Log in, please.