And*_*ers 17 javascript phantomjs
一点背景......我对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);
}
});
Run Code Online (Sandbox Code Playgroud)
这有效:
page.includeJs('http://code.jquery.com/jquery-latest.min.js', function() {
console.log("1: ", comment);
}, comment);
Run Code Online (Sandbox Code Playgroud)
输出:1: Hello World
但不是:
page.includeJs('http://code.jquery.com/jquery-latest.min.js', function(c) {
console.log("1: ", c);
}, comment);
Run Code Online (Sandbox Code Playgroud)
输出: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);
Run Code Online (Sandbox Code Playgroud)
输出:1: http://code.jquery.com/jquery-latest.min.js
看第2件,这有效:
var foo = page.evaluate(function() {
return arguments[0];
}, comment);
console.log("2: ", foo);
Run Code Online (Sandbox Code Playgroud)
输出:2: Hello World
还有这个:
var foo = page.evaluate(function(c) {
return c;
}, comment);
console.log("2: ", foo);
Run Code Online (Sandbox Code Playgroud)
输出:2: Hello World
但不是这个:
var foo = page.evaluate(function() {
return comment;
}, comment);
console.log("2: ", foo);
Run Code Online (Sandbox Code Playgroud)
输出:
ReferenceError:找不到变量:comment
phantomjs://webpage.evaluate():2
phantomjs://webpage.evaluate():3
phantomjs://webpage.evaluate():3
2:null
好消息是,我知道哪些有效,哪些无效,但一致性如何?
为什么includeJs和evaluate?之间存在差异?
将参数传递给匿名函数的正确方法是什么?
nra*_*itz 44
使用PhantomJS理解的棘手问题是有两个执行上下文 - 幻影上下文,它是您的机器的本地上下文,可以访问phantom对象和required模块,以及远程上下文,它存在于window无头浏览器中可以访问您通过网页加载的内容page.load.
您编写的大多数脚本都是在Phantom上下文中执行的.主要的例外是任何内容page.evaluate(function() { ... }).在...这里在远程情况下,这是沙箱运行,而无需访问变量和对象在本地范围内.您可以通过以下方式在两个上下文之间移动数据:
page.evaluate(),或这样传递的值基本上是在每个方向上序列化的 - 你不能用方法传递一个复杂的对象,只能传递像字符串或数组这样的数据对象(我不知道确切的实现,但经验法则似乎是您可以使用JSON序列化的任何内容都可以向任一方向传递).您无法访问page.evaluate()函数外部的变量,就像使用标准Javascript一样,只能访问作为参数明确传入的变量.
所以,你的问题:为什么includeJs和评估之间的区别?
.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);
});
Run Code Online (Sandbox Code Playgroud).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"
Run Code Online (Sandbox Code Playgroud)因此,传递参数的正确方法对于这些不同方法中的函数是不同的.因为injectJs,将使用一组新的参数(至少包括URL)调用回调,因此您要访问的任何变量都需要位于回调的封闭范围内(即您可以在函数的闭包内访问它们) .因为evaluate,传递参数只有一种方法,即将它们包含在传递给evaluate自身的参数中(还有其他方法,但它们很棘手,现在不值得讨论,PhantomJS本身可以使用此功能) .