Что означает "тогда" на самом деле в 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
оператор (выше) выполняется перед my casper.open
заявление и я не знаю, почему.
3 ответов
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();
Примечание: материал обратного вызова / прослушивателя является реализацией шаблон обещание.
then()
просто регистрирует ряд шагов.
run()
и его семейство функций runner, обратных вызовов и слушателей-все это то, что фактически выполняет работу по выполнению каждого шага.
всякий раз, когда шаг завершен, CasperJS будет проверять против 3 флагов:pendingWait
, loadInProgress
и navigationRequested
. Если какой-либо из этих флагов истинен, то ничего не делайте, бездействуйте до более позднего времени (setInterval
стиль). Если ни один из этих флагов не является true, то следующий шаг получит выполненный.
начиная с CasperJS 1.0.0-RC4, существует недостаток, где при определенных обстоятельствах, основанных на времени, метод" try to do next step " будет запущен до того, как 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()
. Проверьте запрос на дополнительную информацию, шаблоны использования и минимальные тестовые файлы.
по словам Документация CasperJS:
then()
подпись: then(Function then)
этот метод является стандартным способом добавления нового шага навигации в стек, предоставляя простую функцию:
casper.start('http://google.fr/');
casper.then(function() {
this.echo("I'm in your google.");
});
casper.then(function() {
this.echo('Now, let me write something');
});
casper.then(function() {
this.echo('Oh well.');
});
casper.run();
вы можете добавить столько шагов, сколько вам нужно. Обратите внимание, что текущий
Casper
экземпляр автоматически связываетthis
ключевое слово для вас в ступенчатая функция.чтобы выполнить все шаги, которые вы определили, называют
run()
способ, и вуаля.Примечание: вы должны
start()
экземпляр casper для использованияthen()
метод.предупреждение: функции шага добавлены в
then()
обрабатываются в двух различных случаях:
- когда предыдущая функция шага казнен,
- когда предыдущий основной HTTP-запрос был выполнен и страница загружается;
обратите внимание, что нет единого определения страница загружается; это когда событие DOMReady было вызвано? Это "все запросы закончены"? Это "вся логика приложения выполняется"? Или "все элементы визуализируются"? Ответ всегда зависит от контекста. Поэтому рекомендуется всегда использовать
waitFor()
семейные методы, чтобы сохранить явный контроль над тем, что вы на самом деле ожидаете.общий трюк-использовать
waitForSelector()
:
casper.start('http://my.website.com/');
casper.waitForSelector("#plop", function() {
this.echo("I'm sure #plop is available in the DOM");
});
casper.run();
за кулисами исходный код Casper.prototype.then
показано ниже:
/**
* Schedules the next step in the navigation process.
*
* @param function step A function to be called as a step
* @return Casper
*/
Casper.prototype.then = function then(step) {
"use strict";
this.checkStarted();
if (!utils.isFunction(step)) {
throw new CasperError("You can only define a step as a function");
}
// check if casper is running
if (this.checker === null) {
// append step to the end of the queue
step.level = 0;
this.steps.push(step);
} else {
// insert substep a level deeper
try {
step.level = this.steps[this.step - 1].level + 1;
} catch (e) {
step.level = 0;
}
var insertIndex = this.step;
while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
insertIndex++;
}
this.steps.splice(insertIndex, 0, step);
}
this.emit('step.added', step);
return this;
};
объяснение:
другими словами, then()
расписание следующего шага в навигации процесс.
, когда then()
вызывается, передается функция как параметр, который должен быть вызван как шаг.
он проверяет, запущен ли экземпляр, а если нет, отображается следующая ошибка:
CasperError: Casper is not started, can't execute `then()`.
далее, он проверяет, если