3

I need to wait some time in PhantomJS. I searched a lot but didn't find an answer. I try this code inside page.open but it doesn't work.

var interval = window.setInterval(function(){ 
    console.log("works");
    clearInterval(interval); 
}, 3000);

I also tried setTimeout but it also didn't help

window.setTimeout(function(){ 
    console.log("works");
}, 3000);

What is a solution for waiting some seconds?

I need to wait 3 seconds between logs: jquery included and works. But these logs appear in console simultaneously.

var page = require("webpage").create();
var url = "https://www.youtube.com";

page.open(url, function(status) {
    if (status == "success"){
        console.log(status);
        if (page.injectJs("jquery.min.js")){
            console.log("jquery included");
            page.evaluate(function(){
                setTimeout(function(){       
                }, 3000);
            });
            console.log("works");
            phantom.exit();
        }       
    }
    else{
        console.log(status);
        phantom.exit();
    }
});
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
levshkatov
  • 477
  • 2
  • 5
  • 16
  • what about `setTimeout()` instead of `setInterval()`? – cl3m Mar 20 '16 at 16:43
  • It can be duplicate, but I can't understand yet what should I do with `page.evaluate`. – levshkatov Mar 20 '16 at 16:47
  • What do you expect to happen? Are you trying to wait inside of the page context (inside `page.evaluate`) and wondering why nothing is printed to the console? – Artjom B. Mar 20 '16 at 16:58
  • @ArtjomB. I have a cycle. In it I click on a button and need to wait some time and then I reload page. In other words, I have two `console.log` and need to `setTimeout` between them – levshkatov Mar 20 '16 at 17:01
  • As for every question which seeks debugging help, what's your definition of *"it doesn't work"*? What do you see and what do you expect to see? Please be more specific. It also wouldn't hurt to show a bigger part of your script to rule out simple mistakes. – Artjom B. Mar 20 '16 at 17:15
  • @ArtjomB. I modified topic with the whole code example. – levshkatov Mar 20 '16 at 17:21
  • @levshkatov you cannot `setTimeout` *between* them, but you can run your second `console.log` in the callback of the `setTimeout` which is effectively the same thing. If this is what youre truly wanting to do: `setTimeout(function() { console.log('works') }, 3000)` is what you want inside the `page.evaluate` – ginman Mar 20 '16 at 17:22
  • You exit phantom before the timeout callback ever executes. I think that's your problem. Move phantom.exit() to inside the setTimeout callback if you want to wait for a few seconds. setTimeout doesn't halt execution of the rest of the script. – dannyjolie Mar 20 '16 at 17:24
  • @ginman I can't run console.log inside `page.evaluate` – levshkatov Mar 20 '16 at 17:28
  • @dannyjolie Also is for `phantom.exit()`. I can't run it inside `evaluate`. – levshkatov Mar 20 '16 at 17:29
  • @levshkatov I see that in the docs that console wont show, and you have no access to the `phantom` object. You can however run pretty much any other code inside of it. At this point, we would need to know what code you are really trying to run, as `setTimeout` is most likely the solution. You can also add a listener to pipe the `console.log` messaging - see the last section in http://phantomjs.org/api/webpage/method/evaluate.html – ginman Mar 20 '16 at 17:34
  • Ah, that's true. It's been a while since I used PhantomJS :) Anyway, this should be what you're looking for, see answer 2 http://stackoverflow.com/questions/11340038/phantomjs-not-waiting-for-full-page-load – dannyjolie Mar 20 '16 at 17:36
  • @ginman It also didn't help if I put `console.log` inside `setTimeout` – levshkatov Mar 20 '16 at 17:43

1 Answers1

6

This is a collection of what is wrong:

  • JavaScript has no sleep function like other languages, because it is single-threaded. This means that a sleep would effectively stop all other processing. So, you cannot use

    console.log("1");
    setTimeout(function(){}, 5000);
    console.log("2");
    

    and expect 2 to be printed 5 seconds after 1. 2 will be printed immediately after 1. You need to use the asynchronous nature of JavaScript:

    console.log("1");
    setTimeout(function(){
        console.log("2");
    }, 5000);
    
  • phantom.exit() must be called when you're done with the script. This means that you need to call it from the setTimeout callback.

  • page.evaluate is the sandboxed page context. You cannot use variables defined outside. As such, you cannot use phantom.exit() inside of page.evaluate(), but you can use the window.callPhantom/page.onCallback pair to get a message from the page context.

  • If you want to receive console messages from the page context, you need to provide a onConsoleMessage event handler.

Full script:

var page = require("webpage").create();
var url = "https://www.youtube.com";

page.onCallback = function(data){
    if (data.type === "exit") {
        phantom.exit();
    }
};
page.onConsoleMessage = function(msg){
    console.log("remote: " + msg);
};
page.open(url, function(status) {
    if (status == "success"){
        console.log(status);
        if (page.injectJs("jquery.min.js")){
            console.log("jquery included");
            page.evaluate(function(){
                setTimeout(function(){
                    console.log("works");
                    window.callPhantom({type: "exit"});
                }, 3000);
            });
        }       
    }
    else{
        console.log(status);
        phantom.exit();
    }
});
Artjom B.
  • 61,146
  • 24
  • 125
  • 222