CasperJS에서 'Then'은 실제로 무엇을 의미합니까?


97

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진술 보다 먼저 실행되고 이유를 모르겠다는 것입니다.


1
저는 여전히 flowcasperjs 의 일반 에 대한 설명을 찾고 있지만 기본적으로 evaluate호출 내에서 casper를 참조 할 수 없다는 것을 발견했습니다 . (즉, 새 URL, 로그, 에코 등을 열 수 없습니다). 그래서 제 경우에는 평가가 호출되었지만 외부 세계와 상호 작용할 방법이 없었습니다.
bendytree 2012-07-23

1
나는 정확히 똑같은 것을 궁금해했지만 물어보기에는 너무 게으르다. 좋은 질문!
Nathan

4
evaluate()phantomjs가 브라우징하는 페이지의 DOM에서 "브라우저"에서 실행되는 코드 용입니다. 그래서 거기에는 casper.open없지만 jQuery가있을 수 있습니다. 따라서 귀하의 예는 의미가 없지만 then()실제로 무엇을하는지 여전히 궁금합니다 .
Nathan

답변:


93

then()기본적으로 스택에 새로운 탐색 단계를 추가합니다. 단계는 두 가지 다른 작업을 수행 할 수있는 자바 스크립트 함수입니다.

  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()우리를 위해 URL을로드하기 위해 CasperJS에 의해 자동으로 추가 된 함수에 주목 하십시오. URL이로드되면 스택에서 사용할 수있는 다음 단계 (즉) step3()가 호출됩니다.

탐색 단계를 정의한 경우 run()순차적으로 하나씩 실행합니다.

casper.run();

각주 : 콜백 / 리스너 항목은 Promise 패턴 의 구현입니다 .


casperjs 1.0.0-RC1에서 "test-steps.js"는 함수 정의 문자열 모음 대신 [object DOMWindow] 모음을 표시합니다.
starlocke

[object DOMWindow] 컬렉션은 여전히 ​​1.0.0-RC4의 결과입니다. 함수 정의가 어디로 갔는지 궁금합니다 ...
starlocke

1
처음에는 CasperJS가 함수를 DOMWindows로 변환하는 새로운 트릭을 수행하고 있다고 생각했지만 문제는 실제로 "return this.toString ()"대 "return step.toString ()"이었습니다. 답변에 대한 편집을 제출했습니다.
starlocke

5
소위 '스택'이 실제로 대기열이 아닙니까? 단계는 순서대로 실행됩니다. 스택 이었으면 3 단계, 2 단계, 1 단계를 예상하지 않았습니까?
Reut Sharabani 2013 년

1
나는 그것이 다음과 같을 것이라고 생각한다 : 당신은 단계의 스택을 가지고있다. 단계를 시작하고 평가합니다. 빈 대기열을 만듭니다. 현재 단계의 처리로 인해 생성 된 모든 단계가이 큐에 들어갑니다. 단계가 평가를 완료하면 큐에서 생성 된 모든 단계가 스택의 맨 위에 배치되지만 큐 내에서 순서는 유지됩니다. (역순으로 스택에 밀어 넣는 것과 동일).
Mark

33

then() 단순히 일련의 단계를 등록합니다.

run() 러너 함수, 콜백 및 리스너 제품군은 실제로 각 단계를 실행하는 작업을 수행합니다.

단계가 완료 될 때마다, CasperJS 3 개 플래그에 대해 확인합니다 : pendingWait, loadInProgress,와 navigationRequested. 이러한 플래그 중 하나라도 참이면 아무것도하지 않고 나중에 유휴 상태로 유지합니다 ( setInterval스타일). 해당 플래그 중 어느 것도 참이 아니면 다음 단계가 실행됩니다.

CasperJS 1.0.0-RC4에서 결함이 존재합니다. 특정 시간 기반 상황에서 CasperJS가 loadInProgress또는 navigationRequested플래그 중 하나를 발생시키기 전에 "다음 단계를 시도"메소드가 트리거됩니다 . 해결책은 플래그가 발생할 것으로 예상되는 단계를 떠나기 전에 플래그 중 하나를 발생시키는 것입니다 (예 : a를 요청하기 전이나 후에 플래그를 올림 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()
}

코드 한 줄에 해당 솔루션을 마무리하기 위해, 나는 도입 blockStep()이 github의의에 끌어 오기 요청 확장 click()clickLabel()사용할 때 우리가 예상 된 동작을 얻을 도움을 보증하는 수단으로 then(). 자세한 정보, 사용 패턴 및 최소 테스트 파일에 대한 요청을 확인하십시오.


1
매우 도움이 훌륭한 통찰력 및에 제안 blockStep, 이럴
브라이언 M. 헌트

우리는 여전히 "최종 답변"솔루션에 대해 논의하고 있습니다. "글로벌 기본값"측면을 구현하면 CasperJS가 도움이되기를 바랍니다.
starlocke 2011

1
그래서 예, 계속 주시하십시오. :)
starlocke '1211.07.16

이에 대한 해결책이 있습니까? 그렇다면 그것은 무엇입니까?
Surender Singh Malik 15.

설명 해주셔서 감사합니다. Ajax를 많이 사용하는 애플리케이션에 대한 Casper 기능 테스트가 항상 무작위로 실패하기 때문에이 동작은 1 년 넘게 저를 죽이고 있습니다.
brettjonesdev 2015

0

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()`.

다음으로 page객체가 null.

조건이 참이면 Casper는 새 page개체를 만듭니다 .

그 후 매개 변수의 then()유효성 step을 검사하여 함수가 아닌지 확인합니다.

매개 변수가 함수가 아닌 경우 다음 오류가 표시됩니다.

CasperError: You can only define a step as a function

그런 다음이 함수는 Casper가 실행 중인지 확인합니다.

Casper가 실행 중이 아니면 then()대기열 끝에 단계를 추가합니다.

그렇지 않고 Casper가 실행 중이면 이전 단계보다 한 단계 더 깊은 하위 단계를 삽입합니다.

마지막으로 then()함수는 step.added이벤트를 생성하여 종료하고 Casper 객체를 반환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.