Что означает "тогда" на самом деле в 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 97

3 ответа:

then() в основном добавляет новый шаг навигации в стеке. Шаг-это функция javascript, которая может делать две разные вещи:

  1. ожидание выполнения предыдущего шага - если таковой имеется
  2. ожидание загрузки запрошенного 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() обрабатываются в двух различных случаях:

  1. когда предыдущая функция шага была выполнено,
  2. когда был выполнен предыдущий основной 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.