Phantomjs 水豚,妖怪,幻影,求值脚本,回调

Phantomjs 水豚,妖怪,幻影,求值脚本,回调,phantomjs,capybara,poltergeist,Phantomjs,Capybara,Poltergeist,我正在使用以下代码,该代码使用带有回调的包来告诉我具有特定csspath的元素何时已完成其所有图像的加载: imagesLoadedScript = "imagesLoaded( '#{csspath}', { background: true }, function(message) { console.log('PHANTOM CLIENT REPORTING: #{csspath} Images Loaded'); return message; })" imagesL

我正在使用以下代码,该代码使用带有回调的包来告诉我具有特定csspath的元素何时已完成其所有图像的加载:

imagesLoadedScript = "imagesLoaded( '#{csspath}', { background: true }, function(message) { console.log('PHANTOM CLIENT REPORTING: #{csspath} Images Loaded'); return message; })"
imagesLoadedScript = imagesLoadedScript.strip.gsub(/\s+/,' ')
@session.evaluate_script(imagesLoadedScript)
在debug打开的情况下检查PhantomJS日志时,console.log语句的计时表明,Capybara/Poltergiest在转到下一个语句之前并没有像预期的那样等待映像加载。我也不能像我所希望的那样从回调内部返回真值或假值

水豚的反应是

{"command_id":"678f1e2e-4820-4631-8cd6-413ce6f4b66f","response":"(cyclic structure)"}
有人知道如何在通过evaluate_脚本执行的函数中从回调函数内部返回值吗

非常感谢。

TLDR;你不能

evaluate_脚本不支持异步函数-必须从传入的函数返回所需的结果。一种方法是执行imagesLoaded脚本,让回调函数设置一个全局变量,然后在一个evaluate_脚本上循环,获取全局变量的结果,直到它符合您的要求—一个非常基本的实现类似于

imagesLoadedScript = "window.allImagesLoaded = false; imagesLoaded( '#{csspath}', { background: true }, function() { window.my_images_loaded = true })"
@session.execute_script(imagesLoadedScript)
while !@session.evaluate_script('window.allImagesLoaded')
  sleep 0.05
end
显然,这可以通过超时功能变得更加灵活,等等


第二个选项是为带有加载过滤器的图像编写自定义水豚选择器类型,尽管由于需要进行背景图像检查,这将变得非常复杂,而且可能太慢而无法使用。

以防万一以后有人发现这一点

我大致按照托马斯·沃尔波尔(Thomas Walpole)在回答中的建议,以一种更迂回的方式,但利用了恶鬼固有的等待能力

#to check that the target has loaded its images, run images loaded
#after a small timeout to allow the page to get the images
#append a marker div to the dom if the images have successfully loaded
imagesLoadedScript = "var item = document.querySelector('#{csspath}');
                      window.scroll(0, item.offsetTop);
                      function imagesDone(path, fn) {
                        imagesLoaded( path, function(instance) {
                           console.log('PHANTOM CLIENT REPORTING: ' + path + ' Images Loaded');
                           fn(true);
                        })
                      }
                      setTimeout(function(){ 
                         imagesDone('#{csspath}', function(done) { 
                           var markerDiv = document.createElement('div'); 
                           markerDiv.id = 'ImagesLoadedMarker'; 
                           document.getElementsByTagName('html')[0].appendChild(markerDiv); 
                         });
                      }, 1000)"

#then we strip the new lines and spaces that we added to make it readable 
imagesLoadedScript = imagesLoadedScript.strip.gsub(/\s+/,' ')
#now we just execute the script as we do not need a return value
@session.execute_script(imagesLoadedScript)
#then we check for the marker, using capybara's inbuilt waiting time
if @session.has_xpath? "//*[@id ='ImagesLoadedMarker']"
   Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images Loaded: Check Time #{Time.now} !!!!!"
   @session.save_screenshot(file_path, :selector => csspath)
else
   Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images NOT Loaded: Check Time #{Time.now} !!!!!"
   @session.save_screenshot(file_path, :selector => csspath)
end

谢谢托马斯,我在上面发布了我的解决方案。我花了一段时间才意识到我在试图做一些不可能的事情。@Tom,这也行得通-你也可以做一些事情,比如在html/body元素中添加一个类,而不是在页面中插入新元素,如果你使用第n个子选择器做任何事情,这可能会搞砸CSS,等等。@Tom-FYI,水豚可能会在下一个版本中支持这个用例——不过不确定在恶灵支持多久之后