Comments 19
«как хотели» и «как получилось, потому что, оказывается, вот что...»
Не могли бы вы вкратце описать принцип работы evaluate
? Метод сериализуется через toString
и передаётся на сторону electron
-а, где eval
-ится? Т.е. всё также как и в casper
, slimer
?
эта цепочка работает с очередью и возвращает в прмис данные.
Любой метод типа .click .type .wait можно рассматривать как частный случай работы evaluate, можно посмотреть в lib/actions.js
Отдельно про передачу функции:
var source = template.execute({ src: String(js_fn), args: args});
this.child.call('javascript', source, done);
под капотом модуль minstache, с шаблоном, куда инжектится функция (как текст)
смотри файл lib/javascript.js
Спасибо. Не ожидал такого подробного ответа. Мне бы хватило простого "да" ) Спросил потому, что у casper.js (slimer, phantom) примерно такой же подход. Очень неудобно. Но, похоже, ввиду того, что по другому никак, с этим приходится мириться.
let text = await nightmare.evaluate((selector)=>{ rerueen document.querySelector(selector).textContent ;}, '#elem-id');
console.log(text);
по сути транспорт связывает код в исполняемом файле с кодом на обрабатываемой странице, никаких вермешелей коллбеков не требуется, все читабельно и просто.
Но тут опять же на вкус и цвет фломастеры разные.
В идеальном случае же:
- можно было бы использовать ту версию JS, коей располагает nodeJS, а не, скажем, es5. Правда тут можно прикрутить что-нибудь вроде
babelEvaluate
- stack-trace-ы ошибок в evaluate-методе показывали не какую-то бесполезную муть, а конкретную строку в тесте. Тут в принципе тоже можно пошаманить с
console.trace
на уровне самого Nightmare. - возможность использовать замыкания, а не дублировать одно и тоже дважды. Но это скорее месты. Не вижу возможности такое реализовать вовсе.
- иметь возможность передать внутрь несериализуемые данные (к примеру set-ы и map-ы).
Ещё у меня был ряд сложностей с undefined-null-NaN. Кажется там всё перегонялось в JSON, и slimer поступал с ними не так, как phantom. Кто-то из ужасно коверкал данные по пути. Постепенно тесты всё больше и больше покрывались набором костылей. Часто получал ошибки вроде circular reference или что-то в таком духе, если куда-нибудь попадали несериализуемые данные.
()=>{
try {} catch(error) { return что-то-что-подверглось_анализу}
}
Эммм, я про тесты. Когда посреди теста сломалось что-то в одном из сотен его evaluate-ов. А стектрейс в консоли содержит чёрти что, потому что упало то оно на самом деле вообще в другом процессе. Тут нужно, чтобы управляющая библиотека склеивала стек-трейсы и грамотно обрабатывала такие ошибки. Теоретически возможно, но на практике пока не встречал.
Если селектор есть изначально, и нужно отловить данные, можно сделать .wait(fn[, arg1, arg2,...])
Пример с тестов:
.wait(function () {
var text = document.querySelector('a').textContent;
return (text === 'A');
});
Получить наличие значения или его отсутствие можно через return !!text
Правда с недавних пор (версия 59 для Mac и Linux, и 60 для Windows) Chrome начал нативно поддерживать headless browsing (можно найти по ключевым словам 'Getting Started with Headless Chrome'), так что есть мнение, что надо начинать больше в ту сторону смотреть…
Если сравнивать с кошмаром, конечно там можно прокидывать низкоуровневые запросы к девтулс хрома, но делается это через экшен кошмара + экшен электрона + вызов обсуждаемых функций.
Плюсы, которые я сразу в хеддлес хром для себя отметил, есть возможность активировать подписки эмиттеров сетевых сообщений, будь то post get запросы к бекэнду или активность на поднятых сокетах, использование авным образом всего апи девтулс.
Минусы, все манипуляции с браузером достаточно низкоуровневые, а потому если требуется что-то быстрое типа 3 кликов и забыть, кошмар явно в выигрыше, а вот если нужно что-то «извращенное», есть смысл посмотреть к хедлессу. Не исключено, что кошмар рано или поздно посмотрят на эту возможность и сделают свое высокоуровневое апи под хеддлес. Время покажет.
Тестирование или парсинг сайтов с динамическим дом и многое другое. Nightmare.js — ему все равно