我是JavaScript的新手,我只是学习使用它的并发模型。现在,我有以下代码,我正在尝试实现busyWait函数:
function captureFile() {
return "screenshots/anthem" + ++numCaptures + ".png"
};
function busyWait(casper, selector, action) {
casper.echo('busyWait', 'INFO');
casper.waitUntilVisible(
selector,
function then() {
this.capture(captureFile());
casper.captureSelector(captureFile(), selector);
casper.echo(selector + ' is Visible', 'INFO');
action(casper);
},
function onTimeout() {
casper.capture(captureFile());
casper.echo('Continue to Wait', 'INFO');
busyWait(casper, selector);
},
1000
);
};
casper.start(anthem_url, function () {
// Try to find the survey and dismiss it.
var surveyID = 'div.fsrFloatingContainer';
busyWait(this, surveyID, function action(casper) {
casper.clickLabel('No, thanks', 'a');
casper.echo('Dismissed Survey', 'INFO');
});
// enter Last Name
var nameID = '#ctl00_MainContent_maincontent_SearchWizard6_LastName';
busyWait(this, nameID, function action(casper) {
casper.sendKeys(nameID, name);
casper.echo('Set Name to: ' + name, 'INFO');
});
this.sendKeys(nameID, name);
this.capture(captureFile());
});
casper.run(function () {
this.exit();
});
运行上面的代码返回:
$casperjs casper_anthem.js
busyWait
busyWait
div.fsrFloatingContainer is Visible
Dismissed Survey
#ctl00_MainContent_maincontent_SearchWizard6_LastName is Visible
Set Name to: Smith
所以,问题是我正在使用回调来实现busyWait循环。当然这不起作用,因为回调在JavaScript中是异步的。我的问题是:如何从回调中强制执行同步行为?
解决方案
事实证明,CasperJS中的then()
函数实际上就是这样做的。
function busyWait(casper, selector, action) {
casper.waitUntilVisible(
selector,
function then() {
casper.echo(selector + ' is Visible', 'INFO');
casper.captureSelector(captureFile(), selector);
action(casper);
casper.capture(captureFile());
},
function onTimeout() {
casper.echo('Continue to Wait for ' + selector, 'INFO');
casper.capture(captureFile());
busyWait(casper, selector, function action(casper) { action(casper) });
},
5000
);
};
casper.start(anthem_url);
// Try to find the survey and dismiss it.
casper.then(function () {
this.capture(captureFile());
busyWait(this, surveyID, function action(casper) {
casper.clickLabel('No, thanks', 'a');
casper.echo('Dismissed Survey', 'INFO');
});
});
// enter Last Name
casper.then(function () {
var nameID = '#ctl00_MainContent_maincontent_SearchWizard6_LastName';
this.waitWhileSelector(surveyID, function () {
busyWait(this, nameID, function action(casper) {
casper.sendKeys(nameID, name);
casper.echo('Set Name to: ' + name, 'INFO');
});
});
});
casper.run();
基本上,我只需要将每个操作放在自己的then()
块中,让CasperJS管理它们的序列化。
答案 0 :(得分:0)
Pointy得到了答案。容器变得可见后发生的任何事情都必须在then
函数中编码,该函数将在主代码块完成后执行。如果您要向用户显示一系列输入,并且每个输入的性质(例如文本或按钮)取决于先前输入的结果,则最终会出现大量嵌套回调。 (这就是它应该如何工作。)
(实际上,你可以通过调用函数来使这看起来更好看。这可以节省缩进,但这意味着有人在查看代码需要一段时间才能找出代码的实际流程。)< / p>
趋势 - 直到你习惯了这一点 - 是编写顺序代码:
first do this ...
then do this ...
then this ...
并且在这种UI中不起作用。