什么必须然后()在CasperJS语句被包裹?如何确定的同步/异步函数执行顺序? [英] What must be wrapped in then() statements in CasperJS? How to determine execution order of sync/async functions?

查看:862
本文介绍了什么必须然后()在CasperJS语句被包裹?如何确定的同步/异步函数执行顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很难的东西确定什么是异步的,什么是不可以在运行CasperJS,哪些必须被包裹在那么()语句,以及正在发生的事情进行评估时

I'm having something of a hard time determining what is asynchronous and what is not while running CasperJS, what must be wrapped in then() statements, and what is going to be evaluated when.

我会碰到什么地方的问题,即有落空break语句,变量的作用域做,或评估()语句,我会着手结束我的所有code,然后在()语句...果然不是问题。

I'll run into a problem somewhere that has to do with a fall-through break statement, variable scope, or the evaluate() statement, and I'll start wrapping all my code in then() statements... which turns out to not be the problem.

我发现我的code在两个层面上运行时我逐句通过它,解析code的评估水平,然后拿出了当时()​​语句。另外,我的打印语句出现在一个有时会莫名的订单。

I notice that my code runs on two levels when I step through it, an evaluation level that parses the code, and then come the then() statements. Also, my print statements appear in a sometimes inexplicable order.

我的问题:如何做到这些则()语句实际上得到排队?我读过的文档,而我有点明白了。我想了解这些规则,并有一些切割和干燥的方法来确定什么是同步的,什么是异步。

My question: how do these then() statements actually get queued? I've read the docs, and I sort of understand. I want to understand the rules and have some cut and dried ways to determine what is sync and what is async.

我甚至看过一本书上的异步编码部分,但没有真正似乎专门解决CasperJS结构。任何资源?

I've even read parts of a book on async coding, but nothing really seems to address CasperJS structure specifically. Any resources?

此外,什么是对的地方把你的话()语句的最佳实践?他们应该在整个宽松穿插,或者他们应该在调用其他人呢?控制主要casper.begin()函数

Also, what's best practice for where to put your then() statements? Should they be peppered liberally throughout, or should they be in the controlling main casper.begin() function that calls the others?

谢谢乡亲们,我已经习惯了PHP。

Thanks folks, I'm used to PHP.

推荐答案

经验法则: 其中包含单词然后和所有CasperJS功能是异步的。:此语句有很多例外。

Rule of thumb: All CasperJS functions which contain the words then and wait are asynchronous. This statement has many exceptions.

CasperJS被组织成一系列的处理脚本的控制流步骤。 则()处理多种PhantomJS /定义一个步骤的结局SlimerJS事件类型。当则()被调用时,传递函数被放入队列一步这是一个简单的JavaScript数组。如果previous一步完成,要么是因为它是一个简单的同步功能,或者是因为CasperJS检测,凡触发特殊事件,下一步将开始执行,直到执行所有步骤重复这一点。

CasperJS is organized as a series of steps that handle the control flow of your script. then() handles the many PhantomJS/SlimerJS event types that define the ending of a step. When then() is called, the passed function is put into a step queue which is a simply JavaScript array. If the previous step finished, either because it was a simple synchronous function or because CasperJS detected that specific events where triggered, the next step will began execution and repeat this until all steps are executed.

所有这些步骤中的功能被绑定到卡斯帕对象,所以你可以参考使用这个的对象。

All those step functions are bound to the casper object, so you can refer to that object using this.

下面的简单脚本显示了两个步骤:

The following simple script shows two steps:

casper.start("http://example.com", function(){
    this.echo(this.getTitle());
}).run();

第一步是隐式异步(阶梯),后面 的open()调用start()。在的start()函数也有一个可选的回调这本身就是在这个脚本中的第二个步骤。

The first step is an implicit asynchronous ("stepped") open() call behind start(). The start() function also takes an optional callback which itself is the second step in this script.

在第一步骤中的页被打开的执行。当页面完全加载,PhantomJS触发 onLoadFinished 事件,CasperJS触发其自己的事件并进行下一步继续。第二步是一个简单的完全同步的功能,所以没有什么花哨发生在这里。当这样做时,CasperJS退出,因为没有更多的步骤来执行。

During the execution of the first step the page is opened. When the page is completely loaded, PhantomJS triggers the onLoadFinished event, CasperJS triggers its own events and continues with the next step. The second step is a simple completely synchronous function, so nothing fancy is happening here. When this is done, CasperJS exits, because there are no more steps to execute.

有一个例外:当一个函数被传递到的run()功能,它将作为最后一步,而不是默认的出口被执行。如果你不叫退出()死()在那里,你将需要终止进程。

There is an exception to this rule: When a function is passed into the run() function, it will be executed as the last step instead of the default exit. If you don't call exit() or die() in there, you will need to kill the process.

就拿下面的例子:

casper.then(function(){
    this.echo(this.getTitle());
    this.fill(...)
    this.click("#search");
}).then(function(){
    this.echo(this.getTitle());
});

如果一个步执行时触发一个事件,表示新页面的加载过程中,那么CasperJS将等待页面加载,直到执行下一个步骤。在这种情况下的点击触发本身引发了<一href=\"http://phantomjs.org/api/webpage/handler/on-navigation-requested.html\"><$c$c>onNavigationRequested从底层浏览器事件。 CasperJS看到这个,直到下一个页面加载使用回调暂停执行。其他类型,比如触发器可能是表单提交,甚至当客户端的JavaScript确实像自己的重定向与 window.open() / window.location的

If during a step execution an event is triggered that denotes the loading of a new page, then CasperJS will wait for the page load until executing the next step. In this case a click was triggered which itself triggered a onNavigationRequested event from the underlying browser. CasperJS sees this and suspends execution using callbacks until the next page is loaded. Other types of such triggers may be form submissions or even when the client JavaScript does something like its own redirect with window.open()/window.location.

当然,这打破了,当我们在谈论一个页面应用程序(使用一个静态的URL)。 PhantomJS无法检测到,例如不同的模板被点击后呈现的,所以不能等到它完成加载(当数据从服务器加载这可能需要一些时间)。如果下面的步骤取决于新页面上,您将需要使用例如 waitUntilVisible()来寻找一个选择所独有的加载页面。

Of course, this breaks down when we are talking about single page applications (with a static URL). PhantomJS cannot detect that for example a different template is being rendered after a click and therefore cannot wait until it is finished loading (this can take some time when data is loaded from the server). If the following steps depend on the new page, you will need to use e.g. waitUntilVisible() to look for a selector that is unique to the page to be loaded.

有些人把它承诺,因为这样的步骤,可以链接。除了名称(则())和一个动作链,那是相似的结束。有没有一个从回调穿过在CasperJS梯级链回调的结果。要么你保存你的结果在一个全局变量或将其添加到卡斯帕对象。那么只有一个有限的错误处理。当遇到一个错误CasperJS将在默认配置死亡。

Some people call it Promises, because of the way steps can be chained. Aside from the name (then()) and an action chain, that's the end of the similarities. There is no result that is passed from callback to callback through the step chain in CasperJS. Either you store your result in a global variable or add it to the casper object. Then there is only a limited error handling. When an error is encountered CasperJS will die in the default configuration.

我preFER尽快你叫叫它Builder模式,因为开始执行的run()和每一个电话是只有在那里放步骤之前,到队列(见第1题)。这就是为什么它没有意义的写步骤功能外同步功能。简单地说,他们没有任何上下文中执行。该页面甚至没有开工负荷。

I prefer to call it a Builder pattern, because the execution starts as soon as you call run() and every call before is only there to put steps into the queue (see 1st question). That is why it doesn't make sense to write synchronous functions outside of step functions. Simply put, they are executed without any context. The page didn't even began loading.

当然,这并不是全部的真相被称这是一个生成器模式。步骤可以嵌套这实际上意味着,如果安排另一个步骤的内部的步骤,将当前步骤之后放入队列,并且其中,已经从当前步骤调度的所有其他步骤之后。 (这是一个很大的步骤!)

Of course this is not the whole truth by calling it a builder pattern. Steps can be nested which actually means that if you schedule a step inside of another step, it will be put into the queue after the current step and after all the other steps that where already scheduled from the current step. (That's a lot of steps!)

下面的脚本是什么我的意思是一个很好的例子:

The following script is a good illustration of what I mean:

casper.on("load.finished", function(){
    this.echo("1 -> 3");
});
casper.on("load.started", function(){
    this.echo("2 -> 2");
});
casper.start('http://example.com/');
casper.echo("3 -> 1");
casper.then(function() {
    this.echo("4 -> 4");
    this.then(function() {
        this.echo("5 -> 6");
        this.then(function() {
            this.echo("6 -> 8");
        });
        this.echo("7 -> 7");
    });
    this.echo("8 -> 5");
});
casper.then(function() {
    this.echo("9 -> 9");
});
casper.run();

第一个数字表示同步code段的脚本的位置,第二个显示实际执行/打印的位置,因为回声()是同步的。

要点:


  • 3号至上

  • 8号印4,5
  • 之间

为了避免混淆,很难发现问题,随时拨打同步功能后异步函数在一个步骤。如果它似乎是不可能的,分裂成多个步骤或考虑递归。

WAITFOR() 等待* 家族中最灵活的功能,因为所有其他功能使用这一个。

waitFor() is the most flexible function in the wait* family, because every other function uses this one.

WAITFOR()时间表(传球只有一个检查功能,并没有别的)的一个步骤。在检查传递到它的功能,直到条件满足或达到(全局)超时被反复调用。当然后和/或 onTimeout 阶跃函数另外通过,将在这些情况下被调用。

waitFor() schedules in its most basic form (passing only one check function and nothing else) one step. The check function that is passed into it, is called repeatedly until the condition is met or the (global) timeout is reached. When a then and/or onTimeout step function is passed additionally, it will be called in those cases.

要注意,如果 WAITFOR()超时,该脚本将停止执行,当你没有在 onTimeout <传递是非常重要的/ code>的回调函数它实际上是一个错误捕捉功能:

It is important to note that if waitFor() times out, the script will stop execution when you didn't pass in the onTimeout callback function which is essentially an error catch function:

casper.start().waitFor(function checkCb(){
    return false;
}, function thenCb(){
    this.echo("inner then");
}, null, 1000).then(function() {
    this.echo("outer");
}).run();

什么是等功能,同时也是异步阶跃函数?

由于1.1 beta3版的也有不遵循经验法则以下附加异步函数:

What are other functions that are also asynchronous step functions?

As of 1.1-beta3 there are the following additional asynchronous functions that don't follow the rule of thumb:

卡斯帕模块:回()向前()重装()重复()开始() withFrame() withPopup()结果
测试仪模块: 开始()

Casper module: back(), forward(), reload(), repeat(), start(), withFrame(), withPopup()
Tester module: begin()

如果你不知道窥视源$ C ​​$ C是否具体函数使用则()等待()

If you're not sure look into the source code whether a specific function uses then() or wait().

事件侦听器可以使用 casper.on(listenerName,回调)注册,他们会使用 casper.emit触发(listenerName,价值观) 。至于CasperJS的内部担心,他们不是异步。异步处理从哪里来的发出()通话躺在功能。 CasperJS只需通过传递最PhantomJS事件,所以这就是那些都是异步的。

Event listeners can be registered using casper.on(listenerName, callback) and they will be triggered using casper.emit(listenerName, values). As far as the internals of CasperJS are concerned, they are not asychronous. The asynchronous handling comes from the functions where those emit() calls lie. CasperJS passes most PhantomJS events simply through, so this is where those are asynchronous.

控制或执行流程是CasperJS执行脚本的方式。当我们打出来的控制流,我们需要管理第二流(甚至更多)。这将极大脚本的开发和维护复杂化。

The control or execution flow is the way CasperJS executes the script. When we break out of the control flow, we need to manage a second flow (or even more). This will complicate the development and maintainability of the script immensely.

为例,你要调用的某处定义的异步函数。让我们假设没有办法重写以这样的方式的功能,即它是同步的。

As example, you want to call an asynchronous function that is defined somewhere. Let's assume that there is no way to rewrite the function in such a way, that it is synchronous.

function longRunningFunction(callback) {
    ...
    callback(data);
    ...
}
var result;
casper.start(url, function(){
    longRunningFunction(function(data){
        result = data;
    });
}).then(function(){
    this.open(urlDependsOnFunResult???);
}).then(function(){
    // do something with the dynamically opened page
}).run();

现在我们有互相依赖两个流。

Now we have two flows which depend on one another.

其他的方式来直接分割流是使用JavaScript函数的setTimeout()的setInterval()。由于CasperJS提供 WAITFOR(),也没有必要使用这些。

Other ways to directly split the flow is by using the JavaScript functions setTimeout() and setInterval(). Since CasperJS provides waitFor(), there is no need to use those.

在控制流必须合并回CasperJS流有通过设置一个全局变量并同时等待它设置一个显而易见的解决方案。

When a control flow must be merged back into the CasperJS flow there is an obvious solution by setting a global variable and concurrently waiting for it to be set.

实施例是一样的在previous问题:

Example is the same as in the previous question:

var result;
casper.start(url, function(){
    longRunningFunction(function(data){
        result = data;
    });
}).waitFor(function check(){
    return result; // `undefined` is evaluated to `false`
}, function then(){
    this.open(result.url);
}, null, 20000).then(function(){
    // do something with the dynamically opened page
}).run();

什么是在测试环境(测试模块)异步?

从技术上来说,没有什么是测试仪模块中的异步的。调用 test.begin()只是执行回调。只有当回调本身使用异步code(即 test.done()里面是一个开始()回调),其他开始()测试用例可以添加到测试用例队列中。

What is asynchronous in the test environment (Tester module)?

Technically, nothing is asynchronous in the tester module. Calling test.begin() simply executes the callback. Only when the callback itself uses asynchronous code (meaning test.done() is called asynchronously inside a single begin() callback), the other begin() test cases can be added to the test case queue.

这就是为什么一个测试用例通常包括一个完整的导航与 casper.start() casper.run(),而不是周围的其他方式:

That is why a single test case usually consists of a complete navigation with casper.start() and casper.run() and not the other way around:

casper.test.begin("description", function(test){
    casper.start("http://example.com").run(function(){
        test.assert(this.exists("a"), "At least one link exists");
        test.done();
    });
});

这是最好坚持筑巢的内部)一个完整的流程开始(,因为开始()运行()通话不会被多个流之间的混合。这使您可以使用每个文件的多个完整的测试用例。

It's best to stick to nesting a complete flow inside of begin(), since the start() and run() calls won't be mixed between multiple flows. This enables you to use multiple complete test cases per file.

注:


  • 当我谈论的同步的功能/执行,我的意思是阻塞调用这实际上可以返回它计算的东西。

  • When I talk about synchronous functions/execution, I mean a blocking call which can actually return the thing it computes.

这篇关于什么必须然后()在CasperJS语句被包裹?如何确定的同步/异步函数执行顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆