Ответ 1
Трудная вещь для понимания с помощью PhantomJS состоит в том, что есть два контекста выполнения - контекст Phantom, который является локальным для вашего компьютера и имеет доступ к объектам phantom
и require
d, а удаленный контекст, который существует в window
браузера без браузера и имеет доступ только к вещам, загруженным в веб-страницы, которые вы загружаете через page.load
.
Большая часть script, которую вы пишете, выполняется в контексте 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); });
-
.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"
Таким образом, правильный способ передачи аргументов in отличается для функций в этих разных методах. Для injectJs
обратный вызов будет вызываться с новым набором аргументов (включая, по крайней мере, URL-адрес), поэтому любые переменные, которые вы хотите получить, должны находиться в области охвата обратного вызова (т.е. У вас есть доступ к ним в пределах закрытие функции). Для evaluate
есть только один способ передать аргументы, которые должны включать их в аргументы, переданные самому evaluate
(есть и другие способы, но они сложны и не стоит обсуждать сейчас, что эта функция имеется в самой PhantomJS).