title: Implementing waitFor functionality with phantomjs-node
body: <p>I have tried and tested - with success - the phantomjs example <a href="https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js" rel="noreferrer">waitFor</a>. However, I am having difficulty implementing it via the <a href="https://github.com/sgentle/phantomjs-node" rel="noreferrer">phantomjs-node</a> module primarily because <code>page.evaluate</code> gets evaluated in a callback.</p>
  
  <p><strong>PhantomJS</strong> Implementation</p>
  
  <pre class="lang-js prettyprint-override"><code>page.open("http://twitter.com/#!/sencha", function () {
      waitFor(function() {
  
          // This here is easy to do as the evaluate method returns immediately
          return page.evaluate(function() {
              return $("#signin-dropdown").is(":visible");
          });
  
      }, function() {
         console.log("The sign-in dialog should be visible now.");
         phantom.exit();
      });
    }
  });
  </code></pre>
  
  <p>However, with <strong>phantomjs-node</strong> the evaluate function gets returned data in a callback:</p>
  
  <pre class="lang-js prettyprint-override"><code>page.evaluate(
      function(){ /* return thing */ },
      function callback(thing) {  /* write code for thing */ }
  )
  </code></pre>
  
  <p>Using <strong>phantomjs-node</strong>, how can I run a function on the page only after an element is visible?</p>
  
  <p>Just in case the link above is dead, here is the implementation of the waitFor function</p>
  
  <pre class="lang-js prettyprint-override"><code>/**
  * Wait until the test condition is true or a timeout occurs. Useful for waiting
  * on a server response or for a ui change (fadeIn, etc.) to occur.
  *
  * @param testFx javascript condition that evaluates to a boolean,
  * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
  * as a callback function.
  * @param onReady what to do when testFx condition is fulfilled,
  * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
  * as a callback function.
  * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
  */
  function waitFor(testFx, onReady, timeOutMillis) {
  var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //&lt; Default Max Timout is 3s
      start = new Date().getTime(),
      condition = false,
      interval = setInterval(function() {
          if ( (new Date().getTime() - start &lt; maxtimeOutMillis) &amp;&amp; !condition ) {
              // If not time-out yet and condition not yet fulfilled
              condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //&lt;    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(); //&lt; Do what it's supposed to do once the condition is fulfilled
                  clearInterval(interval); //&lt; Stop this interval
              }
          }
      }, 250); //&lt; repeat check every 250ms
  };
  </code></pre>
  
  <p>Thanks in advance.</p>