2015-07-10 74 views
0

等待一個元素沒有的setTimeout我正在寫一個函數來等待一個元素,這裏是我的功能:在PhantomJS

function waitForElement(query){ 
    var res="null"; 
    var start=Date.now(); 
    do{ 
     res=page.evaluate(function(query) { 
      return document.querySelector(query)+""; 
     }, query); 
    } while (res==="null" && Date.now()-start<=100000); 
    console.log(Date.now()-start); 
    console.log(res.toString()); 
    return res!=="null"; 
} 

page.open(),我調用這個函數,結果爲「null」。但如果我把函數調用放在setTimeout()中,它就可以工作。

setTimeout(function(){ 
    page.render('afterLogin.png'); 
    waitForElement('ul.coach li'); 
    console.log('Exit'); 
    phantom.exit(); 
}, 50000); 

有人可以向我解釋發生了什麼嗎?

回答

0

page.open回調僅在加載頁面時調用。這並不意味着所有內容都已加載到您的頁面中,並且js已經完全執行。

此外,網頁上的js可能不會立即執行,特別是如果網站使用MVC客戶端框架(如AngularJS或Backbone.js)。在頁面加載事件之後完成很多事情。

使用的setTimeout給你一點延遲,以確保您的網頁完全呈現。

2

JavaScript是單線程的。由於您忙於等待,因此您也會阻止頁面加載和頁面JavaScript的執行。在PhantomJS中不能同步等待。你必須使用一個遞歸和異步方法,如waitFor.js所示的例子PhantomJS文件夾:

/** 
* 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, //< 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 condition is fulfilled 
        clearInterval(interval); //< Stop this interval 
       } 
      } 
     }, 250); //< repeat check every 250ms 
}; 

而且你可以使用它像這樣:

function waitForElement(selector, callback, timeout){ 
    waitFor(function check(){ 
     return page.evaluate(function(selector){ 
      return !!document.querySelector(selector); 
     }, selector); 
    }, callback, timeout); 
} 

setTimeout(function(){ 
    page.render('afterLogin.png'); 
    waitForElement('ul.coach li', function(){ 
     console.log('Exit'); 
     phantom.exit(); 
    }, 100000); 
}, 50000);