4

在 HypnoToad 发送页面后,如何让我的代码执行某些操作?(注意:我正在回答我自己的问题。我发布这个,因为 StackOverflow 指出我之前的问题并没有直接解决我的问题,尽管它确实包含我需要的线索。)

示例代码:

use Mojolicious::Lite;
get "/index" => sub {
   my $c = shift;
   $c->render("renderThis");
   # Do something after rendering
};
app->start('daemon', '-l', 'http://*:8080');

__DATA__
@@ renderThis.html.ep
% layout  "template" ;
<h1>Hello World</h1>

@@ layouts/template.html.ep
<!DOCTYPE html>
<html><head></head><body>
%= content
</body></html>

render 似乎缓冲了它的 http 输出并在代码块完成后发送它。我希望在发送页面后执行某些操作。可以通过将以下内容代替“做某事”注释来观察缓冲。

   sleep 15;
   say "Wow, that was a long time!";

我在win7上,因此仅适用于unix的解决方案将不起作用。

4

2 回答 2

2

上一个问题中的解决方案对我不起作用。(也就是说,simone 在他的评论中链接到的答案。我没有尝试 mob 提供的分叉解决方案。)我的线索来自 Сухой27 的评论。这是我的解决方案:

use Mojolicious::Lite;
use Mojo::IOLoop;
get "/index" => sub {
   my $c = shift;
   $c->render("renderThis");
   Mojo::IOLoop->timer(0 => sub {
      sleep 15;
      say "That was a long time, but at least the page got sent quickly.";
   });
};
app->start('daemon', '-l', 'http://*:8080');

__DATA__
@@ renderThis.html.ep
% layout  "template" ;
<h1>Hello World</h1>

@@ layouts/template.html.ep
<!DOCTYPE html>
<html><head></head><body>
%= content
</body></html>

计时器将其代码从其调用者的执行流程中取出,因此调用函数在计时器的代码执行之前完成并清除其缓冲区(即使时间参数短于调用者完成所需的时间)。

注意:我从实验中得到了解释,而不是代码检查,所以我不知道调用者是否在计时器运行其代码之前刷新其所有缓冲区。我所知道的是,在计时器代码运行之前,render 的 http 响应消失了,STDOUT 被刷新到控制台。我概括了这些观察结果以做出上述陈述。

于 2019-11-30T05:14:24.700 回答
2

您可以将代码附加到事务的完成事件。大多数其他方法不能保证等到实际发送响应,因为它以异步方式发生。

use Mojolicious::Lite;
get "/index" => sub {
   my $c = shift;
   $c->render("renderThis");
   $c->tx->on(finish => sub {
      sleep 15; # this is a really bad idea, use a timer instead
      say "That was a long time, but at least the page got sent quickly.";
   });
};
于 2019-12-02T16:59:39.683 回答