Javascript CasperJS 中的“然后”到底是什么意思
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11604611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What Does 'Then' Really Mean in CasperJS
提问by bendytree
I'm using CasperJS to automate a series of clicks, completed forms, parsing data, etc through a website.
我正在使用 CasperJS 通过网站自动执行一系列点击、完成表单、解析数据等操作。
Casper seems to be organized into a list of preset steps in the form of then
statements (see their example here: http://casperjs.org/quickstart.html) but it's unclear what triggers the next statement to actually run.
Casper 似乎以then
语句的形式组织成一系列预设步骤(请参阅此处的示例:http: //casperjs.org/quickstart.html),但尚不清楚是什么触发了下一条语句的实际运行。
For example, does then
wait for all pending requests to complete? Does injectJS
count as a pending request? What happens if I have a then
statement nested - chained to the end of an open
statement?
例如,是否then
等待所有待处理的请求完成?是否injectJS
算作待处理的请求?如果我有一个then
嵌套的语句 - 链接到open
语句的末尾会发生什么?
casper.thenOpen('http://example.com/list', function(){
casper.page.injectJs('/libs/jquery.js');
casper.evaluate(function(){
var id = jQuery("span:contains('"+itemName+"')").closest("tr").find("input:first").val();
casper.open("http://example.com/show/"+id); //what if 'then' was added here?
});
});
casper.then(function(){
//parse the 'show' page
});
I'm looking for a technical explanation of how the flow works in CasperJS. My specific problem is that my last then
statement (above) runs before my casper.open
statement & I don't know why.
我正在寻找有关流程如何在 CasperJS 中工作的技术解释。我的具体问题是我的最后一条then
语句(上面)在我的casper.open
语句之前运行,我不知道为什么。
采纳答案by NiKo
then()
basically adds a new navigation step in a stack. A step is a javascript function which can do two different things:
then()
基本上在堆栈中添加了一个新的导航步骤。一个 step 是一个 javascript 函数,它可以做两种不同的事情:
- waiting for the previous step - if any - being executed
- waiting for a requested url and related page to load
- 等待上一步 - 如果有 - 正在执行
- 等待请求的 url 和相关页面加载
Let's take a simple navigation scenario:
我们来看一个简单的导航场景:
var casper = require('casper').create();
casper.start();
casper.then(function step1() {
this.echo('this is step one');
});
casper.then(function step2() {
this.echo('this is step two');
});
casper.thenOpen('http://google.com/', function step3() {
this.echo('this is step 3 (google.com is loaded)');
});
You can print out all the created steps within the stack like this:
您可以像这样打印出堆栈中所有创建的步骤:
require('utils').dump(casper.steps.map(function(step) {
return step.toString();
}));
That gives:
这给出了:
$ casperjs test-steps.js
[
"function step1() { this.echo('this is step one'); }",
"function step2() { this.echo('this is step two'); }",
"function _step() { this.open(location, settings); }",
"function step3() { this.echo('this is step 3 (google.com is loaded)'); }"
]
Notice the _step()
function which has been added automatically by CasperJS to load the url for us; when the url is loaded, the next step available in the stack — which is step3()
— is called.
注意_step()
CasperJS自动添加的为我们加载url的函数;加载 url 后,将调用堆栈中可用的下一步 - 即step3()
- 。
When you have defined your navigation steps, run()
executes them one by one sequentially:
定义导航步骤后,run()
依次执行它们:
casper.run();
Footnote:the callback/listener stuff is an implementation of the Promise pattern.
脚注:回调/侦听器内容是Promise 模式的实现。
回答by starlocke
then()
merely registers a series of steps.
then()
仅注册一系列步骤。
run()
and its family of runner functions, callbacks, and listeners, are all what actually do the work of executing each step.
run()
以及它的 runner 函数、回调函数和侦听器系列,这些都是执行每个步骤的实际工作。
Whenever a step is completed, CasperJS will check against 3 flags: pendingWait
, loadInProgress
, and navigationRequested
. If any of those flags is true, then do nothing, go idle until a later time (setInterval
style). If none of those flags is true, then the next step will get executed.
每当一个步骤完成,CasperJS将检查对3个标志:pendingWait
,loadInProgress
,和navigationRequested
。如果这些标志中的任何一个为真,那么什么都不做,闲置直到稍后(setInterval
样式)。如果这些标志都不为真,则将执行下一步。
As of CasperJS 1.0.0-RC4, a flaw exists, where, under certain time-based circumstances, the "try to do next step" method will be triggered before CasperJS had the time to raise either one of the loadInProgress
or navigationRequested
flags. The solution is to raise one of those flags before leaving any step where those flags are expected to be raised (ex: raise a flag either before or after asking for a casper.click()
), maybe like so:
从 CasperJS 1.0.0-RC4 开始,存在一个缺陷,即在某些基于时间的情况下,“尝试执行下一步”方法将在 CasperJS 有时间引发loadInProgress
或navigationRequested
标志之一之前被触发。解决方案是在离开预期会引发这些标志的任何步骤之前引发这些标志之一(例如:在要求 a 之前或之后引发标志casper.click()
),可能如下所示:
(Note: This is only illustrative, more like psuedocode than proper CasperJS form...)
(注意:这只是说明性的,更像是伪代码而不是正确的 CasperJS 形式......)
step_one = function(){
casper.click(/* something */);
do_whatever_you_want()
casper.click(/* something else */); // Click something else, why not?
more_magic_that_you_like()
here_be_dragons()
// Raise a flag before exiting this "step"
profit()
}
To wrap up that solution into a single-line of code, I introduced blockStep()
in this github pull request, extending click()
and clickLabel()
as a means to help guarantee that we get the expected behaviour when using then()
. Check out the request for more info, usage patterns, and minimum test files.
为了将该解决方案打包成一行代码,我blockStep()
在这个 github pull request 中引入了扩展,click()
并clickLabel()
作为一种手段来帮助确保我们在使用then()
. 查看请求以获取更多信息、使用模式和最少测试文件。
回答by Grant Miller
According to the CasperJS Documentation:
根据CasperJS 文档:
then()
then()
Signature:then(Function then)
签名:then(Function then)
This method is the standard way to add a new navigation step to the stack, by providing a simple function:
此方法是向堆栈添加新导航步骤的标准方法,通过提供一个简单的函数:
casper.start('http://google.fr/');
casper.then(function() {
this.echo('I\'m in your google.');
});
casper.then(function() {
this.echo('Now, let me write something');
});
casper.then(function() {
this.echo('Oh well.');
});
casper.run();
You can add as many steps as you need. Note that the current
Casper
instance automatically binds thethis
keyword for you within step functions.To run all the steps you defined, call the
run()
method, and voila.Note:You must
start()
the casper instance in order to use thethen()
method.Warning:Step functions added to
then()
are processed in two different cases:
- when the previous step function has been executed,
- when the previous main HTTP request has been executed and the page loaded;
Note that there's no single definition of page loaded; is it when the DOMReady event has been triggered? Is it "all requests being finished"? Is it "all application logic being performed"? Or "all elements being rendered"? The answer always depends on the context. Hence why you're encouraged to always use the
waitFor()
family methods to keep explicit control on what you actually expect.A common trick is to use
waitForSelector()
:
您可以根据需要添加任意数量的步骤。请注意,当前
Casper
实例this
会在步骤函数中自动为您绑定关键字。要运行您定义的所有步骤,请调用该
run()
方法,瞧。注意:您必须
start()
使用 casper 实例才能使用该then()
方法。警告:添加到的步进函数
then()
在两种不同的情况下进行处理:
- 当上一步函数执行完毕后,
- 当先前的主要 HTTP 请求已执行并加载页面时;
请注意,页面加载没有单一定义;是在 DOMReady 事件被触发时吗?是“所有请求都已完成”吗?是“正在执行所有应用程序逻辑”吗?或者“所有元素都被渲染”?答案总是取决于上下文。因此,为什么鼓励您始终使用
waitFor()
家庭方法来明确控制您实际期望的内容。一个常见的技巧是使用
waitForSelector()
:
casper.start('http://my.website.com/');
casper.waitForSelector('#plop', function() {
this.echo('I\'m sure #plop is available in the DOM');
});
casper.run();
Behind the scenes, the source code for Casper.prototype.then
is shown below:
在幕后,源代码Casper.prototype.then
如下所示:
/**
* Schedules the next step in the navigation process.
*
* @param function step A function to be called as a step
* @return Casper
*/
Casper.prototype.then = function then(step) {
"use strict";
this.checkStarted();
if (!utils.isFunction(step)) {
throw new CasperError("You can only define a step as a function");
}
// check if casper is running
if (this.checker === null) {
// append step to the end of the queue
step.level = 0;
this.steps.push(step);
} else {
// insert substep a level deeper
try {
step.level = this.steps[this.step - 1].level + 1;
} catch (e) {
step.level = 0;
}
var insertIndex = this.step;
while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
insertIndex++;
}
this.steps.splice(insertIndex, 0, step);
}
this.emit('step.added', step);
return this;
};
Explanation:
解释:
In other words, then()
schedules the next step in the navigation process.
换句话说,then()
安排导航过程的下一步。
When then()
is called, it is passed a function as a parameter which is to be called as a step.
当then()
被调用时,它被传递一个函数作为参数,该函数将作为一个步骤被调用。
It checks if an instance has started, and if it has not, it displays the following error:
它检查实例是否已启动,如果尚未启动,则显示以下错误:
CasperError: Casper is not started, can't execute `then()`.
Next, it checks if the page
object is null
.
接下来,它检查page
对象是否为null
。
If the condition is true, Casper creates a new page
object.
如果条件为真,Casper 将创建一个新page
对象。
After that, then()
validates the step
parameter to check if it is not a function.
之后,then()
验证step
参数以检查它是否不是函数。
If the parameter is not a function, it displays the following error:
如果参数不是函数,则会显示以下错误:
CasperError: You can only define a step as a function
Then, the function checks if Casper is running.
然后,该函数会检查 Casper 是否正在运行。
If Casper is not running, then()
appends the step to the end of the queue.
如果 Casper 未运行,then()
则将步骤附加到队列的末尾。
Otherwise, if Casper is running, it inserts a substep a level deeper than the previous step.
否则,如果 Casper 正在运行,它会插入一个比上一步更深的子步骤。
Finally, the then()
function concludes by emitting a step.added
event, and returns the Casper object.
最后,该then()
函数以发出一个step.added
事件结束,并返回 Casper 对象。