使用 CasperJS 等待循环中的选择器
Waiting for a selector in a loop with CasperJS
我想做循环等待选择器只要找到的对象不满足指定条件。我写了下面的代码。
casper.then(
function(){
var need_exit = false;
this.echo('enter loop');
var i = 1;
while (!need_exit){
this.echo('check exit');
// check, if chat was finished
if (this.exists('div#chat > p')){
need_exit = true;
this.echo('exit loop');
}
// wait new message
else {
this.echo('wait msg ' + datetime());
var selector = 'div#chat tr:nth-child('+i+')';
try{
this.waitForSelector(selector,
function(){
var msg_selector = 'div#chat tr:nth-child('+i+') > td:nth-child(2)';
var inf = this.getElementInfo(msg_selector);
this.echo(inf['text']);
i++;
},
null,
5000);
}
catch(err){
this.echo('[wait timeout]');
}
need_exit = true;
}
}
}
);
问题是在找到项目或超时已过后,迭代不断地相互跟随而不是前进到下一个迭代。为什么会发生这种情况以及如何正确处理?
问题是所有 then*
和 wait*
调用都是异步步骤函数。这就是为什么你不能在它们周围使用循环。解决这个问题的正常方法是使用递归函数:
这是您函数的重新构想版本:
casper.waitContinuouslyUntilSelector = function(checkRow, finalSelector, then, onTimeout, timeout, i){
// TODO: remove the `this.echo()` calls from this function
i = i || 1;
this.then(function(){
if (this.exists(finalSelector)) {
this.echo('finalSelector found');
this.then(then);
return;
}
this.waitForSelector(checkRow(i), function _then(){
this.waitContinuouslyUntilSelector(checkRow, finalSelector, then, onTimeout, timeout, i+1);
}, function _onTimeout(){
if (this.exists(finalSelector)) {
this.echo('finalSelector found');
this.then(then);
} else {
this.echo('finalSelector not found');
if (typeof onTimeout !== "function") {
throw new CasperError("Final selector was not found and next row was not loaded");
}
this.then(onTimeout);
}
}, timeout);
});
return this;
}
你可以这样使用它:
casper.then(function(){
var bindingExitSelector = 'div#chat > p';
var rowSelectorFunc = function(i){
return 'div#chat tr:nth-child('+i+') > td:nth-child(2)';
};
this.waitContinuouslyUntilSelector(rowSelectorFunc, bindingExitSelector);
});
如果没有更多行加载并且 "final" <p>
也不存在,则会出现超时错误。如果你想阻止这种情况,你需要传入一个 onTimeout
回调:
this.waitContinuouslyUntilSelector(rowSelectorFunc,
bindingExitSelector,
null,
function _onTimeout(){
this.echo("Failed to load the next row and didn't found the final selector; continue...");
});
我想做循环等待选择器只要找到的对象不满足指定条件。我写了下面的代码。
casper.then(
function(){
var need_exit = false;
this.echo('enter loop');
var i = 1;
while (!need_exit){
this.echo('check exit');
// check, if chat was finished
if (this.exists('div#chat > p')){
need_exit = true;
this.echo('exit loop');
}
// wait new message
else {
this.echo('wait msg ' + datetime());
var selector = 'div#chat tr:nth-child('+i+')';
try{
this.waitForSelector(selector,
function(){
var msg_selector = 'div#chat tr:nth-child('+i+') > td:nth-child(2)';
var inf = this.getElementInfo(msg_selector);
this.echo(inf['text']);
i++;
},
null,
5000);
}
catch(err){
this.echo('[wait timeout]');
}
need_exit = true;
}
}
}
);
问题是在找到项目或超时已过后,迭代不断地相互跟随而不是前进到下一个迭代。为什么会发生这种情况以及如何正确处理?
问题是所有 then*
和 wait*
调用都是异步步骤函数。这就是为什么你不能在它们周围使用循环。解决这个问题的正常方法是使用递归函数:
这是您函数的重新构想版本:
casper.waitContinuouslyUntilSelector = function(checkRow, finalSelector, then, onTimeout, timeout, i){
// TODO: remove the `this.echo()` calls from this function
i = i || 1;
this.then(function(){
if (this.exists(finalSelector)) {
this.echo('finalSelector found');
this.then(then);
return;
}
this.waitForSelector(checkRow(i), function _then(){
this.waitContinuouslyUntilSelector(checkRow, finalSelector, then, onTimeout, timeout, i+1);
}, function _onTimeout(){
if (this.exists(finalSelector)) {
this.echo('finalSelector found');
this.then(then);
} else {
this.echo('finalSelector not found');
if (typeof onTimeout !== "function") {
throw new CasperError("Final selector was not found and next row was not loaded");
}
this.then(onTimeout);
}
}, timeout);
});
return this;
}
你可以这样使用它:
casper.then(function(){
var bindingExitSelector = 'div#chat > p';
var rowSelectorFunc = function(i){
return 'div#chat tr:nth-child('+i+') > td:nth-child(2)';
};
this.waitContinuouslyUntilSelector(rowSelectorFunc, bindingExitSelector);
});
如果没有更多行加载并且 "final" <p>
也不存在,则会出现超时错误。如果你想阻止这种情况,你需要传入一个 onTimeout
回调:
this.waitContinuouslyUntilSelector(rowSelectorFunc,
bindingExitSelector,
null,
function _onTimeout(){
this.echo("Failed to load the next row and didn't found the final selector; continue...");
});