使用Mojo::UserAgent时wait返回空的问题

最近可能又需要写web应用, 于是认真读了一下凯哥写的和翻译的有关Mojo的文章.

之前用Mojo主要是用它的Mojo::UserAgent来快速的抓取页面信息. 但是写的过程中参考的官方例子的竟然是有问题的(现在已经修复). 后来仔细读了一下文档才解决, 但是没有明白. 现在看了相关的文章, 终于明白为什么这么设计了. 在这里简单总结一下.

先上一段代码:

Blocking parallel requests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Mojo::UserAgent;
use DDP;

my $ua = Mojo::UserAgent->new;
$ua->max_redirects(3);

# Blocking parallel requests (does not work inside a running event loop)
my $delay = Mojo::IOLoop->delay;
for my $url ('stackoverlow.com', 'github.com', 'en.wikipedia.org') {
    my $end = $delay->begin();
    $ua->get($url => {'Haha' => 'Hehe'} => sub {
        my ($ua, $tx) = @_;

        $end->('BE CAUTIOUS, this will be ommited', $tx->res->dom->at('title')->text);
    });
}

my @titles = $delay->wait;
p @titles;

上述代码是可以正常运行的, 需要注意的是$delay->begin()$end->(p1, p2)这两句. 之前官方的例子是省略了p1, 导致$delay->wait总是返回为空. 官方的对begin的阐述是这样子的:

Increment active event counter, the returned callback can be used to decrement the active event counter again. Arguments passed to the callback are queued in the right order for the next step or “finish” event and “wait” method, the first argument will be ignored by default.

之前一直没弄明白为什么这么设计, 直到看了这篇文章的这段代码:

code from above blog
1
2
3
4
5
6
7
8
9
10
11
12
13
any '/all' => sub {
  my $self = shift;
  $self->render_later;
  my $delay = Mojo::IOLoop->delay(sub{
    my $delay = shift;
    my @titles = map { $_->res->dom->at('title')->text } @_;
    $self->render_dumper(@titles);
  });
  $delay->steps(sub{
    my $delay = shift;
    $self->ua->get( $_ => $delay->begin ) for @urls;
  });
};

注意倒数第三行的delay->begin. Mojo::UserAgent的回调传进去的参数为$ua$tx, 在finish阶段仅仅需要处理$tx. 出于这样的原因因此默认就省略了第一个参数. 对于这种非阻塞的调用显得极为简洁.

Comments