Phantomjs page.evaluate and q deferred issue

Phantomjs page.evaluate and q deferred issue

本文关键字:deferred issue and page evaluate Phantomjs      更新时间:2023-09-26

我正在尝试将"Q"承诺库与PhantomJS一起使用,但下面的代码不起作用。

app.evaluate_page=function(page){
    var deferred = q.defer();
    console.log("Before the page evaluation");
    page.evaluate(function(){
        deferred.resolve(page);
    });
    return deferred.promise;
};

以下是错误

Before the page evaluation
ReferenceError: Can't find variable: deferred
  phantomjs://webpage.evaluate():2
  phantomjs://webpage.evaluate():3
  phantomjs://webpage.evaluate():3

看起来它无法找到在外部作用域中定义的延迟变量,这很奇怪。相同类型的代码适用于具有回调的其他方法,如page.open方法。

以下代码只是按预期工作,不确定为什么上面的代码不能。

app.openPage = function(options){
  var deferred = q.defer();
  page.open(options.url,function(status){
      if(status!=="success"){
          deferred.reject(new Error("Page could not be loaded at "+ options.url ));
      }
      else {
          deferred.resolve(page);
      }
  });
  return deferred.promise;
};
page.evaluate

浏览器进程中运行,无法访问您的变量。

您同步拥有page变量,因此您不需要此处的承诺。

正如@slaks提到的,page.evaluate回调函数在沙盒环境中运行。

官方文件明确指出page.evaluate

在网页上下文中计算给定函数。这 执行是沙盒化的,网页无法访问幻像 对象,它无法探测自己的设置。

然而,你可以传入和传出参数,但正如官方文档所述:

注意:参数和返回值的求值函数必须 是一个简单的原始对象。经验法则:如果可以的话 通过 JSON 序列化,那就没问题了。

截至目前(2016年10月),深入研究该主题,这似乎是一个悬而未决的问题。

  1. GitHub上有一个关于使用page.evaluate启用承诺的未决问题:等待对承诺模式的支持 ·问题 #14166 ·Ariya/Phantomjs
  2. 有一个实验性 API 可以从网页上下文启用回调函数:onCallback |幻影
  3. 等待网页准备就绪的官方方法是扩展 Waitfor.js示例

我使用第三种方法的个人混合。

这是我main.js文件:

'use strict';
var wasSuccessful = phantom.injectJs('./lib/waitFor.js');
var page = require('webpage').create();
page.open('http://foo.com', function(status) {
  if (status === 'success') {
    page.includeJs('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js', function() {
      waitFor(function() {
        return page.evaluate(function() {
          if ('complete' === document.readyState) {
            return true;
          }
          return false;
        });
      }, function() {
        var fooText = page.evaluate(function() {
          return $('#foo').text();
        });
        phantom.exit();
      });
    });
  } else {
    console.log('error');
    phantom.exit(1);
  }
});

还有lib/waitFor.js文件(它只是从 phantomjs waitfor.js示例中复制和粘贴waifFor()函数):

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function() {
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if(!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    // console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condi>
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
}

此方法不是异步的,但至少我可以确保在尝试使用它们之前已加载所有资源。