Что значит "тогда" в CasperJS
Я использую CasperJS для автоматизации серии кликов, заполненных форм, анализа данных и т.д. через веб-сайт.
Кажется, Каспер организован в список предустановленных шагов в форме операторов then
(см. их пример здесь: http://casperjs.org/quickstart.html), но неясно, что запускает следующий оператор.
Например, then
ожидает завершения всех ожидающих запросов? Рассчитывает ли injectJS
как ожидающий запрос? Что произойдет, если у меня есть инструкция then
, вложенная в цепочку в конце инструкции open
?
casper.thenOpen('http://example.com/list', function(){
casper.page.injectJs('/libs/jquery.js');
casper.evaluate(function(){
var id = jQuery("span:contains('"+itemName+"')").closest("tr").find("input:first").val();
casper.open("http://example.com/show/"+id); //what if 'then' was added here?
});
});
casper.then(function(){
//parse the 'show' page
});
Я ищу техническое объяснение того, как поток работает в CasperJS. Моя конкретная проблема заключается в том, что мой последний оператор then
(выше) работает до моего оператора casper.open
, и я не знаю почему.
Ответы
Ответ 1
then()
в основном добавляет новый шаг навигации в стек. Шаг - это функция javascript, которая может выполнять две разные вещи:
- ожидание предыдущего шага - если выполнено -
- ожидание запроса URL-адреса и связанной страницы для загрузки
Возьмем простой сценарий навигации:
var casper = require('casper').create();
casper.start();
casper.then(function step1() {
this.echo('this is step one');
});
casper.then(function step2() {
this.echo('this is step two');
});
casper.thenOpen('http://google.com/', function step3() {
this.echo('this is step 3 (google.com is loaded)');
});
Вы можете распечатать все созданные шаги в стеке следующим образом:
require('utils').dump(casper.steps.map(function(step) {
return step.toString();
}));
Это дает:
$ casperjs test-steps.js
[
"function step1() { this.echo('this is step one'); }",
"function step2() { this.echo('this is step two'); }",
"function _step() { this.open(location, settings); }",
"function step3() { this.echo('this is step 3 (google.com is loaded)'); }"
]
Обратите внимание на функцию _step()
, которая автоматически добавлена CasperJS для загрузки URL-адреса для нас; при загрузке URL-адреса вызывается следующий шаг, доступный в стеке - step3()
-.
Когда вы определили свои шаги навигации, run()
выполняет их поочередно:
casper.run();
Сноска: материал обратного вызова/прослушивателя представляет собой реализацию шаблона Promise.
Ответ 2
then()
просто регистрирует последовательность шагов.
run()
и его семейство функций бегуна, обратных вызовов и слушателей - все, что на самом деле выполняет работу по выполнению каждого шага.
Всякий раз, когда шаг завершен, CasperJS будет проверять три флага: pendingWait
, loadInProgress
и navigationRequested
. Если какой-либо из этих флагов истинен, то ничего не делайте, простаивайте до более позднего времени (setInterval
style). Если ни один из этих флагов не является истинным, следующий шаг будет выполнен.
Как и в случае с CasperJS 1.0.0-RC4, существует недостаток, когда в определенных временных условиях метод "попытаться сделать следующий шаг" будет срабатывать до того, как у CasperJS было время поднять либо один из loadInProgress
или navigationRequested
. Решение состоит в том, чтобы поднять один из этих флагов, прежде чем покинуть любой шаг, на котором ожидается, что эти флаги будут подняты (например: поднять флаг до или после запроса casper.click()
), возможно, так:
(Примечание: это только иллюстративное, более похожее на psuedocode, чем на правильную форму CasperJS...)
step_one = function(){
casper.click(/* something */);
do_whatever_you_want()
casper.click(/* something else */); // Click something else, why not?
more_magic_that_you_like()
here_be_dragons()
// Raise a flag before exiting this "step"
profit()
}
Чтобы обернуть это решение в одну строку кода, я ввел blockStep()
в этот github запрос pull, расширяя click()
и clickLabel()
как средство, чтобы гарантировать, что мы получим ожидаемое поведение при использовании then()
. Проверьте запрос на получение дополнительной информации, шаблонов использования и минимальных тестовых файлов.