“然后”在CasperJS中真正意味着什么

时间:2012-07-22 22:50:10

标签: javascript casperjs

我正在使用CasperJS通过网站自动执行一系列点击,完成表单,解析数据等。

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语句之前运行。我不知道为什么。

3 个答案:

答案 0 :(得分:93)

then()基本上会在堆栈中添加新的导航步骤。步骤是一个javascript函数,可以做两件事:

  1. 等待上一步 - 如果有 - 正在执行
  2. 等待请求的网址和相关网页加载
  3. 我们来看一个简单的导航场景:

    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)'); }"
    ]
    

    注意CasperJS自动添加的_step()函数为我们加载网址;当加载url时,将调用堆栈中可用的下一步 - 即step3()

    定义导航步骤后,run()会逐个执行导航步骤:

    casper.run();
    

    脚注:回调/监听器内容是Promise pattern的实现。

答案 1 :(得分:33)

then()只是注册了一系列步骤。

run()及其运行函数,回调和侦听器系列都是执行每一步的实际工作。

每当步骤完成时,CasperJS将检查3个标志:pendingWaitloadInProgressnavigationRequested。如果这些标志中的任何一个为真,则不执行任何操作,直到稍后的时间(setInterval样式)。如果这些标志都不为真,那么下一步将被执行。

从CasperJS 1.0.0-RC4开始,存在一个缺陷,在某些基于时间的情况下,在CasperJS有时间筹集其中任何一个之前,将触发“尝试下一步”方法。 1}}或loadInProgress标志。解决方案是在离开任何希望引发这些标志的步骤之前引发其中一个标志(例如:在要求navigationRequested之前或之后提出标志),也许是这样:

(注意:这只是说明性的,更像是psuedocode而不是正确的CasperJS形式......)

casper.click()

为了将该解决方案整理成一行代码,我在此github pull request中引入了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()click()作为帮助保证的方法我们在使用clickLabel()时得到了预期的行为。查看有关更多信息,使用模式和最低测试文件的请求。

答案 2 :(得分:0)

根据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() Casper实例才能使用then()方法。

     

警告::在两种不同情况下处理添加到 then() 的步进函数:

     
      
  1. 执行上一步功能后,
  2.   
  3. 先前的主要HTTP请求已执行并且页面已加载;
  4.   
     

请注意,没有页面加载的单一定义;是何时触发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();

幕后的source code for 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

如果条件为true,Casper将创建一个新的page对象。

然后,then()验证step参数是否不是函数。

如果参数不是函数,则会显示以下错误:

CasperError: You can only define a step as a function

然后,该功能检查Casper是否正在运行。

如果Casper没有运行,则then()将步骤附加到队列的末尾。

否则,如果Casper正在运行,它将插入比上一步更深的子步骤。

最后,then()函数通过发出step.added事件结束,并返回Casper对象。