使用phantomjs-node实现waitFor功能
Implementing waitFor functionality with phantomjs-node
我尝试并测试了phantomjs示例waitFor,并取得了成功。然而,我很难通过phantomjs-node模块实现它,主要是因为page.evaluate
在回调中得到评估。
PhantomJS
实现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();
});
}
});
然而,对于phantomjs-node, evaluate函数在回调中获得返回的数据:
page.evaluate(
function(){ /* return thing */ },
function callback(thing) { /* write code for thing */ }
)
使用phantomjs-node,我如何在页面上运行一个函数后,元素是可见的?
为了防止上面的链接失效,下面是waitFor函数的实现
/**
* 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
};
今天遇到了这个问题,想分享一下我的解决方案。
// custom helper function
function wait(testFx, onReady, maxWait, start) {
var start = start || new Date().getTime()
if (new Date().getTime() - start < maxWait) {
testFx(function(result) {
if (result) {
onReady()
} else {
setTimeout(function() {
wait(testFx, onReady, maxWait, start)
}, 250)
}
})
} else {
console.error('page timed out')
ph.exit()
}
}
第一步是创建新的wait
函数。它采用与原waitFor
函数相同的参数,但工作方式略有不同。在触发测试函数testFx
的回调之后,我们必须递归地运行wait
函数,而不是使用间隔。另外,请注意,您实际上不需要为start
传递一个值,因为它是自动设置的。
wait(function (cb) {
return page.evaluate(function ()
// check if something is on the page (should return true/false)
return something
}, cb)
}, function () { // onReady function
// code
}, 5000) // maxWait
在这个例子中,我将testFx
函数的回调设置为page.evaluate
的回调,它根据是否能够在页面上找到某些元素返回true/false值。或者,您可以为page.evaluate
创建回调,然后从中触发testFx
回调,如下所示:
wait(function (cb) {
return page.evaluate(function ()
// check if something is on the page (should return true/false)
return something
}, function(result) {
var newResult = doSomethingCrazy(result)
cb(newResult)
}
}, function () { // onReady function
// code
}, 5000) // maxWait
我为phantomjs-node编写了一个名为phridge的替代方案。它没有将所有函数调用和赋值转换为异步操作,而是在PhantomJS中执行整个函数。
我认为你的问题可以这样解决:
phridge.spawn()
.then(function (phantom) {
return phantom.openPage(url);
})
.then(function (page) {
return page.run(selector, function (selector, resolve, reject) {
// this function runs inside PhantomJS bound to the webpage instance
var page = this;
var intervalId = setInterval(function () {
var hasBeenFound = page.evaluate(function (selector) {
return Boolean(document.querySelector(selector));
}, selector);
if (hasBeenFound === false &&
/* check if there is still some time left */) {
// wait for next interval
return;
}
clearInterval(intervalId);
if (hasBeenFound) {
resolve();
} else {
reject(new Error("Wait for " + selector + " timeout"));
}
}, 100);
});
})
.then(function () {
// element has been found
})
.catch(function (err) {
// element has not been found
});
我最近创建了一个相当简单的节点模块,将waitFor移植到节点:https://gist.github.com/joseym/1d01edbcc40a7698f55a#file-phantomjs-waitfor-js
var async = require('async');
module.exports = waitFor;
/**
* waitFor port used with
* @see {@link https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js}
* @see {@link https://github.com/sgentle/phantomjs-node}
* @callback testFx - Test function, will repeat until true or timeout limit is reached
* @callback onReady - Fires if/when `testFx` passes.
* @param {(number|boolean|string)} [timeOut=false] - If defined and falsey or string value of`forever`
* then `waitFor` will run until `testFx` passes without
* timing out, otherwise pass a number in miliseconds.
*/
function waitFor(testFx, onReady, timeOut) {
var maxtimeOutMillis = typeof timeOut !== 'undefined' ? timeOut : 5000 // Default Max Timout is 5s if not defined
, start = new Date().getTime()
, isAsync = testFx.length > 0
, passing = undefined
;
async.until(
function Test() {
return typeof passing !== 'undefined';
},
function Action(cb) {
setTimeout(function(){
if (!maxtimeOutMillis || maxtimeOutMillis == 'forever' || new Date().getTime() - start < maxtimeOutMillis) {
// If a callback is passed to `testFx` we'll handle that.
function useCallback(){
passing = arguments[0]
return cb();
};
passing = (function(){
return (typeof(testFx) === "string" ? eval(testFx) : testFx).apply(this, arguments);
})(isAsync ? useCallback : undefined);
if(!isAsync) cb();
} else {
return cb(new Error('`waitFor` timeout'));
}
}, 250);
},
function Done(err) {
return (function(){
return (typeof(onReady) === "string" ? eval(onReady) : onReady).apply(this, arguments);
})(err, passing);
}
);
}
- 添加文字和评论功能更新Div
- JavaScript打印功能使日历停止工作
- 每当您在选择器内移动鼠标时,悬停功能就会重复
- 如何防止网页加载后自动启动功能
- 除修剪外的其他功能
- 悬停功能触发器
- 使用angularjs向浏览器发送servlet响应(下载功能)
- 删除CKEditor工具栏按钮,但不删除功能
- 异步facebook功能
- 如何将chrome扩展功能移植到移动设备(特别是jquery和trello)
- jQuery滚动功能只工作一次
- Graphiti中是否有任何工具提示功能
- React redux初始化功能,无论状态变化如何
- 在哪里可以学习ECMAScript标准中尚未包含的JavaScript功能
- 正在获取select上的功能id
- Rhino打印功能
- 使用(navigator.geolocation)检测浏览器功能错误
- 主体单击删除功能上的输入框宽度
- JQuery使用相同的功能自动完成各种输入文本
- 使用phantomjs-node实现waitFor功能