2

I'm currently executing PhantomJS (from PHP) to render some HTML reliably (utilizing 3rd party js libraries that can't be easily replicated in PHP) and then sending the rendered HTML back to the client.

$fh = fopen('/dev/shm/graph-'.$sig.'.html', 'w');
fwrite($fh, $html);
fclose($fh);
$stime = microtime(true);
$res = exec('/usr/bin/phantomjs /home/me/www/js/render_svg.js '.
                  escapeshellarg($sig), $output, $return_var);
var_dump(microtime(true)-$stime);  // 400 ms
print implode("\n", $output);
exit();

render_svg.js:

var system = require('system');
var fs = require('fs');
var page = require('webpage').create();
page.onLoadFinished = function() {
    system.stdout.write(page.content);
    phantom.exit(0);
};
content = '';
f = fs.open('/dev/shm/graph-'+system.args[1]+'.html', 'r');
content += f.read();
page.content = content;

The execution time for PhantomJS is around 400ms which is super, but probably too much of a delay to use in production. Is there any way of getting this down by e.g. not using exec to fire up phantomjs each time, but having it already running in the background?

EoghanM
  • 25,161
  • 23
  • 90
  • 123

3 Answers3

2

You could try the webserver module: http://phantomjs.org/api/webserver/

There is a tutorial on it here: http://benjaminbenben.com/2013/07/28/phantomjs-webserver/

(If you try this, I'd love to hear how you get on and how latency compares to your current 400ms using exec.)

BTW, I think there was a recent change in the mongoose license, making it incompatible with the PhantomJS license. So it is possible this feature will disappear in future releases. (There was also talk of switching in an alternative library to mongoose, in which case it may not disappear!)

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • 2
    Yes! This did it :) I timed the delay for onLoadFinished to around 125ms. Total time for the request has come down from 400ms to 147ms, so the webserver solution adds around 20ms in contrast to the ~250ms added when using exec. I'll write up what the solution looks like in another answer for reference. – EoghanM Feb 04 '14 at 10:34
2

Answer thanks to Darren Cook:

$fh = fopen('/dev/shm/graph-'.$sig.'.full.html', 'w');
fwrite($fh, $html);
fclose($fh);
$stime = microtime(true);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:8080');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'sig='.$sig);
$output = curl_exec($ch);
curl_close($ch);
var_dump(microtime(true)-$stime); // 150ms
print $output;
exit();

render_svg.js:

var system = require('system');
var fs = require('fs');
var page = require('webpage').create();
var server = require('webserver').create();
var service = server.listen('127.0.0.1:8080', function(request, response) {
    var stime = new Date();
    content = '';
    f = fs.open('/dev/shm/graph-'+request.post['sig']+'.full.html', 'r');
    content += f.read();
    page.content = content;
    page.onLoadFinished = function() {
        response.statusCode = 200;
        response.write(page.content);
        response.close();
    };    
});
EoghanM
  • 25,161
  • 23
  • 90
  • 123
-2

In short, no. PhantomJS can't be run as a daemon or server so you'll need to execute this script every time. If you want to improve performance, you should try finding another method of rending the html.

smithbh
  • 347
  • 1
  • 7