Что означает "тогда" на самом деле в 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
стиль). Если ни один из этих флагов не является истинным, то следующий шаг будет получить выполненный.по состоянию на 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()
экземпляр Каспер для того, чтобы использовать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()`.
далее, он проверяет, если чтобы проверить, если это не функция.
если параметр не является функцией, он отображает следующую ошибку:
CasperError: You can only define a step as a function
затем функция проверяет, работает ли Каспер.
если Каспер не работает,
then()
добавляет шаг в конец очереди.в противном случае, если Casper работает, он вставляет подшаг на уровень глубже, чем предыдущий шаг.
наконец,
then()
функция завершает путем испускатьstep.added
событие, и возвращает объект Casper.