一点背景..。我对javascript和phantom.js都是个新手,所以我不知道这是javascript还是phantom.js bug (特性?)。
下面的代码成功完成(很抱歉,缺少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.valuate():2
phantomjs://webpage.valuate():3
phantomjs://webpage.valuate():3
2:空
好消息是,我知道什么是有效的,什么是无效的,但是如何保持一点一致性呢?
为什么includeJs
和evaluate
会有不同
向匿名函数传递参数的正确方式是什么?
发布于 2012-09-01 06:26:28
要理解PhantomJS的棘手之处在于有两个执行上下文-幻影上下文,它位于您的机器本地,可以访问phantom
对象和require
d模块;远程上下文,它存在于无头浏览器的window
中,只能访问您通过page.load
加载的网页中加载的内容。
您编写的大部分脚本都是在Phantom上下文中执行的。主要的例外是page.evaluate(function() { ... })
中的任何内容。这里的...
是在被沙箱保护的远程上下文中执行的,不能访问本地上下文中的变量和对象。您可以通过以下方式在两个上下文之间移动数据:
page.evaluate()
的函数返回值,或者这样传递的值本质上是在每个方向上序列化的-不能用方法传递复杂的对象,只能传递像字符串或数组这样的数据对象(我不知道确切的实现,但经验法则似乎是,任何可以用JSON序列化的东西都可以在这两个方向上传递)。您不能访问page.evaluate()
函数之外的变量,就像使用标准Javascript一样,只能访问作为参数显式传递的变量。
那么,您的问题是:为什么includeJs和之间存在差异?
.includeJs(url, callback)
接受一个回调函数,该函数在幻影上下文中执行,显然接收url作为其第一个参数。除了它的参数之外,它还可以访问(就像任何普通的JavaScript函数一样)其封闭作用域中的所有变量,包括示例中的comment
。它在回调函数后不需要额外的参数列表--当你在回调函数中引用comment
时,你引用的是一个外部变量,而不是一个函数参数。var foo =“});
.evaluate(function, args*)
”;page.includeJs('http://code.jquery.com/jquery-latest.min.js',console.log(){ //此回调函数在幻影上下文页面中执行(“jQuery是在远程上下文中加载的。”);//它可以访问外部作用域变量,包括“幻象”页面(foo,nowDoMoreStuff);var接受要执行的函数以及传递给它的零个或多个参数(以某种序列化形式)。您需要在函数签名中命名参数,例如function(a,b,c)
,或者使用arguments
对象访问它们-它们不会自动与您传入的变量具有相同的名称。var foo = "stuff";var bar =“用于远程页面的东西”;var result = page.evaluate( function (bar2) { //此函数在远程上下文中执行//它可以访问您在$(‘title’).html(Bar2)中传递的DOM、远程库和参数;//但不能访问外部作用域vars return typeof foo +“”+ typeof bar;},bar);console.log(result);// " undefined "
因此,对于不同方法中的函数,传入参数的正确方式是不同的。对于injectJs
,回调将使用一组新的参数(至少包括URL)来调用,因此您想要访问的任何变量都需要在回调的封闭范围内(即您可以在函数的闭包中访问它们)。对于evaluate
来说,只有一种方法可以传递参数,那就是将它们包含在传递给evaluate
本身的参数中(还有其他方法,但是这些方法都很棘手,现在这个特性已经在PhantomJS中可用了,所以不值得讨论)。
https://stackoverflow.com/questions/12222856
复制相似问题