17

少し背景...私はjavascriptとphantom.jsに少し慣れていないので、これがjavascriptまたはphantom.jsのバグ(機能?)かどうかわかりません。

以下は正常に完了します(phantom.exit()が欠落していることをお詫びします。完了したら、ctrl + cを実行する必要があります)。

var page = require('webpage').create();
var comment = "Hello World";

page.viewportSize = { width: 800, height: 600 };
page.open("http://www.google.com", function (status) { 
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    } else {
        page.includeJs('http://code.jquery.com/jquery-latest.min.js', function() {
            console.log("1: ", comment);
        }, comment);

        var foo = page.evaluate(function() {            
            return arguments[0];
        }, comment);

        console.log("2: ", foo);            
    }
});

これは機能します:

page.includeJs('http://code.jquery.com/jquery-latest.min.js', function() {
    console.log("1: ", comment);
}, comment);

出力1: Hello World

だがしかし:

page.includeJs('http://code.jquery.com/jquery-latest.min.js', function(c) {
    console.log("1: ", c);
}, comment);

出力1: http://code.jquery.com/jquery-latest.min.js

そしてそうではありません:

page.includeJs('http://code.jquery.com/jquery-latest.min.js', function() {
    console.log("1: ", arguments[0]);
}, comment);

出力1: http://code.jquery.com/jquery-latest.min.js

2番目のピースを見ると、これは機能します。

var foo = page.evaluate(function() {            
    return arguments[0];
}, comment);

console.log("2: ", foo);

出力2: Hello World

この:

var foo = page.evaluate(function(c) {           
    return c;
}, comment);

console.log("2: ", foo);

出力2: Hello World

しかし、これではありません:

var foo = page.evaluate(function() {            
    return comment;
}, comment);

console.log("2: ", foo);

出力

ReferenceError:変数が見つかりません:コメント

phantomjs://webpage.evaluate():2

phantomjs://webpage.evaluate():3

phantomjs://webpage.evaluate():3

2:null

良いニュースは、何が機能し、何が機能しないかを知っていますが、少し一貫性はどうですか?

includeJsなぜとの違いはevaluate

匿名関数に引数を渡す適切な方法はどれですか?

4

1 に答える 1

44

PhantomJSで理解するのが難しいのは、2つの実行コンテキストがあることです。マシンにローカルでphantomオブジェクトとrequiredモジュールにアクセスできるPhantomコンテキストとwindow、ヘッドレスブラウザ内にのみ存在するリモートコンテキストです。を介してロードしたWebページにロードされたものにアクセスできますpage.load

作成するスクリプトのほとんどは、ファントムコンテキストで実行されます。主な例外は、内のすべてですpage.evaluate(function() { ... })。hereは、...ローカルコンテキストの変数やオブジェクトにアクセスせずに、サンドボックス化されたリモートコンテキストで実行されます。次の方法で、2つのコンテキスト間でデータを移動できます。

  • に渡された関数から値を返すpage.evaluate()、または
  • その関数に引数を渡します。

このように渡された値は、基本的に各方向にシリアル化されます-メソッドを使用して複雑なオブジェクトを渡すことはできず、文字列や配列などのデータオブジェクトのみを渡すことができます(正確な実装はわかりませんが、大まかなルールはJSONでシリアル化できるものはすべて、どちらの方向にも渡すことができます)。標準のJavascriptの場合のように、関数の外部の変数にアクセスすることはできません。引数として明示的に渡す変数にのみアクセスできます。page.evaluate()

それで、あなたの質問:なぜincludeJsとevaluateの違いは?

  • .includeJs(url, callback)Phantomコンテキスト内で実行されるコールバック関数を受け取り、最初の引数としてURLを受け取るようです。引数に加えて、例を含め、囲んでいるスコープ内のすべての変数に(通常のJavaScript関数と同様に)アクセスできcommentます。コールバック関数の後に追加の引数リストは必要ありませcomment。コールバック内で参照する場合、関数の引数ではなく、外部変数を参照しています。

    var foo = "stuff";
    page.includeJs('http://code.jquery.com/jquery-latest.min.js', function() {
        // this callback function executes in the Phantom context
        console.log("jQuery is loaded in the remote context.");
        // it has access to outer-scope variables, including "phantom"
        nowDoMoreStuff(foo, page);
    });
    
  • .evaluate(function, args*)実行する関数とそれに渡す0個以上の引数を取ります(シリアル化された形式で)。たとえば、関数シグネチャで引数に名前を付けるfunction(a,b,c)か、オブジェクトを使用して引数にargumentsアクセスする必要があります。引数には、渡した変数と同じ名前が自動的に付けられることはありません。

    var foo = "stuff";
    var bar = "stuff for the remote page";
    
    var result = page.evaluate(function(bar2) {
        // this function executes in the remote context
        // it has access to the DOM, remote libraries, and args you pass in
        $('title').html(bar2);
        // but not to outer-scope vars
        return typeof foo + " " + typeof bar;
    }, bar);
    
    console.log(result); // "undefined undefined"
    

したがって、引数を渡す正しい方法は、これらのさまざまなメソッドの関数によって異なります。の場合injectJs、コールバックは新しい引数のセット(少なくとも、URLを含む)で呼び出されるため、アクセスする変数はすべて、コールバックの囲んでいるスコープ内にある必要があります(つまり、関数のクロージャ内でそれらにアクセスできます)。 。の場合evaluate、引数を渡す方法は1つしかありません。それは、引数をそれ自体に渡される引数に含めることevaluateです(他の方法もありますが、この機能がPhantomJS自体で利用できるようになったため、注意が必要で、説明する価値はありません)。 。

于 2012-08-31T22:26:28.330 に答える