将参数传递给page.includeJs()和page.evaluate()中的匿名函数 [英] Passing arguments to anonymous function inside page.includeJs() and page.evaluate()

查看:163
本文介绍了将参数传递给page.includeJs()和page.evaluate()中的匿名函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一点背景......我对javascript和phantom.js有点新,所以我不知道这是一个javascript还是phantom.js bug(功能?)。

A little background... I'm a little new to javascript, and to phantom.js, so I don't know if this is a javascript or phantom.js bug (feature?).

以下内容成功完成(对于缺少的phantom.exit(),您只需要在完成后进行ctrl + c):

The following completes successfully (sorry for the missing phantom.exit(), you'll just have to ctrl+c once you are done):

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

查看第二部分,这有效:

Looking at the 2nd piece, this works:

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:找不到变量:comment

ReferenceError: Can't find variable: comment

phantomjs://webpage.evaluate():2

phantomjs://webpage.evaluate():2

phantomjs://webpage.evaluate():3

phantomjs://webpage.evaluate():3

phantomjs://webpage.evaluate():3

phantomjs://webpage.evaluate():3

2:null

好消息是,我知道什么有效,什么无效但是,但是一点点的一致性怎么样?

The good news is, I know what works and what doesn't, but how about a little consistency?

为什么 includeJs 之间的区别?评估

将参数传递给匿名函数的正确方法是什么?

Which is the proper way to pass arguments to an anonymous function?

推荐答案

使用PhantomJS理解棘手的事情是有两个执行上下文 - 幻影上下文,它是你的机器本地的,可以访问幻像 object和 require d模块,以及存在于窗口中的远程上下文无头浏览器,只能访问通过 page.load 加载的网页中加载的内容。

The tricky thing to understand with PhantomJS is that there are two execution contexts - the Phantom context, which is local to your machine and has access to the phantom object and required modules, and the remote context, which exists within the window of the headless browser and only has access to things loaded in webpages you load via page.load.

您编写的大部分脚本都是在Phantom上下文中执行的。主要的例外是 page.evaluate(function(){...})中的任何内容。 ... 此处在远程上下文中执行,该上下文是沙箱,无法访问本地上下文中的变量和对象。您可以通过以下方式在两个上下文之间移动数据:

Most of the script you write is executed in the Phantom context. The main exception is anything within page.evaluate(function() { ... }). The ... here is executed in the remote context, which is sandboxed, without access to the variables and objects in your local context. You can move data between the two contexts by:


  • 从传递给 page.evaluate的函数返回一个值( ),或

  • 将参数传递给该函数。

这样传递的值基本上是在每个方向上序列化的 - 你不能用方法传递一个复杂的对象,只能传递像字符串或数组这样的数据对象(我不知道确切的实现,但经验法则似乎你可以用任何方向传递任何你可以用JSON序列化的东西。您可以访问 page.evaluate()函数之外的变量,就像使用标准Javascript一样,只能访问您明确传入的变量作为参数。

The values thus passed are essentially serialized in each direction - you can't pass a complex object with methods, only a data object like a string or an array (I don't know the exact implementation, but the rule of thumb seems to be that anything you can serialize with JSON can be passed in either direction). You do not have access to variables outside the page.evaluate() function, as you would with standard Javascript, only to variables you explicitly pass in as arguments.

所以,你的问题:为什么includeJs和评价之间存在差异?


  • .includeJs(url,callback)接受在 Phantom 上下文中执行的回调函数,显然是接收网址作为其第一个参数。除了它的参数之外,它还可以访问其封闭范围内的所有变量(就像任何普通的JavaScript函数一样),包括示例中的 comment 。在回调函数之后它获取额外的参数列表 - 当你在回调中引用 comment 时,你引用的是外部变量,而不是函数参数。

  • .includeJs(url, callback) takes a callback function that executes within the Phantom context, apparently receiving the url as its first argument. In addition to its arguments, it has access (like any normal JavaScript function) to all variables in its enclosing scope, including comment in your example. It does not take an additional argument list after the callback function - when you reference comment within the callback, you're referencing an outside variable, not a function argument.

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 *)接受一个函数来执行,并传递零个或多个参数(以某种序列化形式)。您需要在函数签名中命名参数,例如函数(a,b,c),或使用参数对象来访问它们 - 它们不会自动拥有与传入的变量名称相同。

  • .evaluate(function, args*) takes a function to execute and zero or more arguments to pass to it (in some serialized form). You need to name the arguments in the function signature, e.g. function(a,b,c), or use the arguments object to access them - they won't automagically have the same names as the variables you pass in.

    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 ,只有一种方法可以传入参数,即将它们包含在传递给 evaluate 的参数中本身(还有其他方式,但它们很棘手,不值得讨论,因为PhantomJS本身可以使用此功能)。

    So the correct way to pass arguments in is different for the functions in these different methods. For injectJs, the callback will be called with a new set of arguments (including, at least, the URL), so any variables you want to access need to be in the callback's enclosing scope (i.e. you have access to them within the function's closure). For evaluate, there is only one way to pass in arguments, which is to include them in the arguments passed to evaluate itself (there are other ways, too, but they're tricky and not worth discussing now that this feature is available in PhantomJS itself).

    这篇关于将参数传递给page.includeJs()和page.evaluate()中的匿名函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆