Сегодня мы поговорим об очень важной вещи — о том как устроен iMacros и по какой логике он работает. Это фундамент, понимание принципов которого поможет вам избежать многих ошибок и писать код осознанно. Я расскажу о том, как он работает, о чем нужно думать, когда переделываешь макрос с iim на js и о коварном this
и window
.
Логика работы движка iMacros
iMacros — это расширение, для своей работы использует JavaScript-движок браузера, а значит у него есть доступ к JavaScript Extensions API — грубо говоря, это библиотеки различных функций для работы с сетью, файлами, операционной системой и т.д. Получается, что все скрипты iMacros запускаются на виртуальной Javascript-машине, для простоты будем называть ее процессом, а лучше инстансом(instance). Могу привести тупое сравнение, инстансы — это нечто, похожее на процессы Google Chrome в диспетчере задач для каждой вкладки браузера. Только в нашем случае, мы не увидим их в диспетчере задач, они запускаются внутри процесса firefox.
По сути своей, iMacros — это очень простое расширение, которое позволяет запускать произвольный Jaavscript-код. Для упрощения, для простых смертных сделали команды, вроде «URL GOTO=..» и т.д. — по факту это просто обертка над Javascript-кодом, как и управляющие команды, вроде этой «iimDisplay()».
То есть, когда вы нажимаете на кнопку «Воспроизвести» в панели iMacros, создается новый инстанс и в нем выполняется скрипт, неважно какого он формата .iim или .js.
Давайте посмотрим и проанализируем, как все работает. Для начала возьмем простой скрипт в формате .iim(стандартный формат iMacros), который ждет 3 секунды и переходит на страницу.
TAB T=1
WAIT SECONDS=3
URL GOTO=https://ya.ru/
Обратите внимание, когда мы нажимаем кнопку «Воспроизвести», создается новый инстанс и в нем выполняется скрипт, неважно какого он формата .iim или .js, кнопка становится неактивной до тех пор, пока скрипт не закончит свою работу, а также становятся доступны «Пауза» и «Стоп».
«Генерал очевидность» — скажите вы, но это важный момент, при создании скриптов на JS, поведение этих кнопок может изменится и они могут перестать работать. Вы должны понимать, что у iMacros есть набор встроенных функций, которые обрабатываются расширением и влияют на отображение и доступность кнопок. Но когда мы начинаем писать код на JS, который работает отдельно, он не влияет на переключение состояний кнопок.
Вот наглядный пример в формате .js:
- iimPlayCode('WAIT SECONDS=3');
- window.setTimeout(function () {
- alert('Nagibaka');
- },2000);
Запустив этот пример, понаблюдайте за кнопкой воспроизведения, она будет 3 секунды неактивна, пока выполняется стандартная команда аймакроса, а потом станет активна, типа скрипт завершил свою работу. А по факту еще через 2 секунды вылезет сообщение. Понимаете к чему я клоню? У нас есть возможность запускать свои скрипты и они будут выполняться в независимости от того, что показывает интерфейс на боковой панели аймакроса. Но и это еще не все, при каждом нажатии кнопки «Воспроизвести» — поднимается новый инстанс, что честно говоря не очень разумно с точки зрения потребления памяти и вычислительных ресурсов. Вы легко можете это сами проверить.
Давайте немного изменим код:
- window.setInterval(function () {
- window.console.log('Nagibaka ' + Math.random());
- },2000);
Теперь откройте консоль(F12->Console) и нажмите кнопку «Воспроизвести» в панели аймакрос один раз. Каждые 2 секунды вы будете получать сообщение в консоль. Теперь нажмите на эту кнопку еще несколько раз подряд, каждое ваше нажатие будет поднимать отдельный инстанс, процесс, виртуальную Javascript-машину, называйте как хотите и там будет независимо выполняться ваш код.
Тут есть одна интересная деталь, если вы откроете новый таб, то в нем в вашу консоль тоже будут приходить сообщения. Но, если вы закроете первый таб, в котором запускали много раз скрипт — то сообщения перестанут приходить. Отсюда вывод — все инстансы привязываются к текущему табу(окну) и выполняются в контексте данного окна (window). При закрытии окна, скрипты удаляются из памяти.
Контекст выполнения. ‘window’ и this.
Те, из вас, кто знаком с Javascript, наверно заметили, что я везде использую window.setTimeout() вместо стандартного setTimeout(). При обычном использовании JS можно и так и так использовать, но у нас это не прокатит. Чтобы понять почему, создайте простой js-макрос:
- window.console.log(this);
Запустите сначала его просто в консоли фаербага и вы увидите что-то вроде Window ya.ru
— кликнув на этот объект — вы сможете посмотреть его свойства и методы. Там вы найдете и метод console
к примеру. А теперь запустите тот же код через iMacros. Вы увидите что-то вроде "Object { imns={...}, window=Window, content=Window, ещё...}"
. Именно поэтому в js-методах часто придется добавлять «window.» Получается, что весь код выполняется вне объекта window и по иерархии, функции iMacros стоят выше, чем все методы внутри window, это также значит, если мы в консоли браузера попытаемся вызвать методы аймакроса, типа playCode(), то из консоли они будут недоступны, а из нашего скрипта вполне себе.
Давайте немного посмотрим, что у нас в this обитает:
Помимо объекта window, свойственного для каждой веб-страницы, мы видим стандартные управляющие функции iMacros, объект content и объект imns. Если покопаться в imns — можно найти всякие полезные функции, типа чтения\записи файлов на диск с помощью js, используя функционал расширений и библиотеки Firefox.
При выводе текста в консоль, справа в фаербаге можно увидеть надписи типо «jsplayer.js (строка 187)» — и если поковыряться в папке расширения iMacros — можно даже найти этот файл и посмотреть что и как там работает. Этот плеер — просто небольшой js-скрипт для управления запуском и остановкой скриптов, обработкой команд, изменением интерфейса расширения и т.д.
У этого плеера есть еще одна особенность. Я говорю про команду iimPlayCode(), которой мы будем пользоваться чаще всего, для воспроизведения нашего js-кода. Давайте возьмем пример простого макроса формата .iim:
- SET !TIMEOUT 1
- URL GOTO=https://nagibaka.ru/
Тут мы выставляем время, отведенное на работу последующей команды. В данном случае мы будем ждать 1 секунду и если страница не загрузится, то вылезет ошибка или код будет дальше исполняться, если выставлено игнорирование ошибок. Попробуем переписать на JS — сразу покажу правильный и неправильный вариант.
- // Работает корректно
- iimPlayCode('SET !TIMEOUT 1\nURL GOTO=https://nagibaka.ru/');
- // Таймаут не установится, а будет стандартный в 60 секунд
- iimPlayCode('SET !TIMEOUT 1\n');
- iimPlayCode('URL GOTO=https://nagibaka.ru/');
Вы должны понимать, что при выполнении команды iimPLayCode(), расширению необходимо отобразить список команд в окошке слева, управлять отображением кнопок Воспроизвести\Стоп\Пауза. Поэтому каждый вызов iimPlayCode() выполняется также, как если бы это отдельные макросы запускались.
iMacros-переменные между скриптами не передаются и недоступны! Поэтому используем JS-переменные!
Нужно всегда помнить об этом, тогда будет меньше ошибок, особенно при работе с iimExtract и другими методами.