将参数传递给匿名函数里面page.includeJs()和page.evaluate()(Passi

2019-06-27 16:07发布

一点背景......我有点新的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

纵观第二张,这工作:

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:空

好消息是,我知道什么可行,什么不可行,但如何对一个小的一致性?

为什么之间的差别includeJsevaluate

这是参数传递给一个匿名函数的正确方法?

Answer 1:

棘手的事情与PhantomJS明白的是,有两个执行上下文-幻影背景下,这是本地的机器,并先后获得了phantom对象,并require模块里,和远程背景下,在其中存在window无头的浏览器只能访问你通过网页载入速度加载的东西page.load

大部分你写的剧本是在幻影上下文中执行。 主要的例外是内的任何page.evaluate(function() { ... })...这里是在远程情况下,这是沙箱运行,而无需访问变量和对象在本地范围内。 您可以通过移动两个上下文之间的数据:

  • 返回从传递函数的值,以page.evaluate()
  • 在该函数传递参数。

因此,传递的值在每个方向基本上是序列化 - 你不能通过使用方法复杂的对象,只有像一个字符串或数组(我不知道确切的实施,但凭经验数据对象似乎是任何事情,你可以用JSON序列化可以在任一方向传递)。 您没有外部访问变量page.evaluate()函数,就像使用标准的JavaScript,只有变量,你明确地传递作为参数。

所以,你的问题: 为什么includeJs和评估之间的区别?

  • .includeJs(url, callback)取该幻影上下文中执行,显然接收到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*)取一个函数来执行和零个或多个参数传递给它(在某些序列化形式)。 您需要命名参数的函数签名,如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 ,只有一个办法在参数传递,这是它们包含在传递给参数evaluate本身(还有其他的方式,太多,但他们是棘手的,不值得讨论,现在这个功能在PhantomJS可用本身)。



文章来源: Passing arguments to anonymous function inside page.includeJs() and page.evaluate()