web-dev-qa-db-ja.com

CasperJSで「その後」とはどういう意味ですか

CasperJSを使用して、Webサイトを通じて一連のクリック、完成したフォーム、データの解析などを自動化します。

Casperは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ステートメントの前に実行されることです。その理由はわかりません。

97
bendytree

then()は、基本的にスタックに新しいナビゲーションステップを追加します。ステップは、2つの異なることを実行できる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)'); }"
]
_

URLを読み込むためにCasperJSによって自動的に追加された_step()関数に注目してください。 URLがロードされると、スタックで使用可能な次のステップ(step3())が呼び出されます。

ナビゲーション手順を定義したら、run()はそれらを1つずつ順番に実行します。

_casper.run();
_

脚注:コールバック/リスナーは Promiseパターン の実装です。

93
NiKo

then()は単に一連のステップを登録するだけです。

run()とそのランナー関数、コールバック、およびリスナーのファミリーはすべて、各ステップを実行する作業を実際に行うものです。

ステップが完了するたびに、CasperJSは3つのフラグに対してチェックします:pendingWaitloadInProgress、およびnavigationRequested。これらのフラグのいずれかが真である場合、何もせず、後でアイドル状態になります(setIntervalスタイル)。これらのフラグのいずれも真でない場合、次のステップが実行されます。

CasperJS 1.0.0-RC4の時点で、特定の時間ベースの状況下で、CasperJSがloadInProgressまたはnavigationRequestedフラグ。解決策は、これらのフラグのいずれかを上げてから、それらのフラグが立てられると予想されるステップを離れることです(例:casper.click()を要求する前後にフラグを立てます)。

(注:これは単なる例であり、適切な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()
}

そのソリューションを1行のコードにまとめるために、このgithubにblockStep()を導入しました プルリクエストclick()およびclickLabel()then()を使用するときに期待される動作が得られることを保証することを意味します。詳細、使用パターン、最小限のテストファイルについては、リクエストをご覧ください。

33
starlocke

CasperJS Documentationによると

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()に追加されたステップ関数は、2つの異なるケースで処理されます。

  1. 前のステップ関数が実行されたとき、
  2. 前のメインHTTP要求が実行され、ページがロードされたとき;

page loaded;の単一の定義はないことに注意してください。 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()`.

次に、pageオブジェクトがnullであるかどうかを確認します。

条件が真の場合、Casperは新しいpageオブジェクトを作成します。

その後、then()stepパラメーターを検証して、それが関数でないかどうかを確認します。

パラメータが関数ではない場合、次のエラーが表示されます。

CasperError: You can only define a step as a function

次に、関数はCasperが実行されているかどうかを確認します。

Casperが実行されていない場合、then()はキューの最後にステップを追加します。

それ以外の場合、Casperが実行されている場合、前のステップよりも深いレベルのサブステップを挿入します。

最後に、then()関数は step.added イベントを発行して終了し、Casperオブジェクトを返します。

0
Grant Miller