Perl Promises 和 Anyevent 中没有继续 **then**

问题描述 投票:0回答:1

我尝试做同步功能

#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use AE;
use Time::Piece;
use Promises backend =>['AnyEvent'], 'deferred';
use feature q(say);
use Data::Dumper;

$| = 1;
my $inputs = 'starting';
my $w2; $w2 = AE::timer 5, 0, sub {
    say '***> AE::io timer : pass 5sec : ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
    say '***> making : inputs = next';
    $inputs = 'next';
};
my $w3; $w3 = AE::timer 15, 15, sub {
    say 'AE::io timer : passed 15 sec : ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
};
sub delay {
    my ($dl, $cb) = @_;
    my $t;
    $t = AE::timer $dl, 0, sub {
        say '===> delay : delayed ', $dl, ' sec';
        undef $t;
        $cb->() if ref $cb eq 'CODE';
    };
}
sub my_p_await{
    my ($sec, $cond, $cb) = @_;
    my $d = deferred;
    say '===> my_p_await: staring...with ',$sec, ' sec: ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
    my $result = eval { $cond->() };
    if(!$result) {
        say '===> my_p_await: condition is false';
        delay($sec, sub {
            $cb->() if ref $cb eq 'CODE';
            my_p_await($sec, $cond, $cb);
        });
    }else{
        say '===> my_p_await: condition is true';
        $d->resolve;
        return;
    }
    return $d->promise;
}

deferred->resolve->promise->then( sub {
    my_p_await(3, sub { $inputs eq 'next'},sub {say '0: cb..'} )
})
->then( sub {
    say '';
    say '****>==> Time: 0: ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
});

AE::cv->recv;

和结果

===> my_p_await: staring...with 3 sec: 2024-08-26 18:55:13
===> my_p_await: condition is false
===> delay : delayed 3 sec
0: cb..
===> my_p_await: staring...with 3 sec: 2024-08-26 18:55:16
===> my_p_await: condition is false
***> AE::io timer : pass 5sec : 2024-08-26 18:55:18
***> making : inputs = next
===> delay : delayed 3 sec
0: cb..
===> my_p_await: staring...with 3 sec: 2024-08-26 18:55:19
===> my_p_await: condition is true
AE::io timer : passed 15 sec : 2024-08-26 18:55:28

它不会继续下一步然后,所以我从来没有看到'****>==>时间:0:'消息。

即使 AE 计时器在 15 秒后触发,AnyEvent 运行也没有问题。

第一个 5 秒计时器被触发,将 $inputs 字符串发送到 'next'

所以 my_p_await 的条件为真。

我做错了什么?

perl promise anyevent
1个回答
0
投票

首先,

deferred->resolve->promise->then( sub {
    my_p_await(3, sub { $inputs eq 'next'},sub {say '0: cb..'} )
})
->then( sub {
    say '';
    say '****>==> Time: 0: ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
});

是一种复杂的书写方式

my_p_await(3, sub { $inputs eq 'next'},sub {say '0: cb..'} )
->then( sub {
    say '';
    say '****>==> Time: 0: ',
        Time::Piece->new(AE::now, "%s")->strftime("%Y-%m-%d %H:%M:%S");
});

在这两种情况下,

then
代码都会等待
my_p_await
返回的承诺得到解决。如果条件最初为 false,则这种情况永远不会在您的代码中发生。

当然,另一个调用

my_p_await
返回的承诺会返回一个已解决的承诺。但这是一个不同的承诺。

因此,我们需要确保首次调用

my_p_wait
返回的承诺得到解决。


首先,Promises(.pm) 声称遵循 Promises 规范,但它没有提供捕获异常的 Promise 构造函数。所以我要使用固定的

deferred

# Promises doesn't follow the spec.
# Replace deferred with a correct one.
sub deferred {
   my $cb = shift;  # Optional.

   my $promise = Promises::deferred;

   if ( $cb ) {
      eval {
         $cb->(
            sub { $promise->resolve( @_ ) },
            sub { $promise->reject( @_ ) },
         );
      };

      $promise->reject( $@ ) if $@;
   }

   return $promise;
}

接下来,我将解决“成功”回调和承诺的混合问题,这使事情变得复杂。

从技术上讲,

delay
不会混合“成功”回调和承诺。但我将把它转换为使用 Promise 来保持一致性。

sub delay {
   my $sec = shift;

   return deferred sub {
      my $resolve = shift;

      say ts(), " ===> delay: Delaying $sec s.";

      my $t;
      $t = AE::timer $sec, 0, sub {
         say ts(), " ===> delay: Delayed $sec s.";
         undef $t;
         $resolve->();
      };
   };
}

现在让我们从

my_p_wait
中消除“成功时”回调(并重命名)。

sub polling_cond_wait {
   my ( $sec, $cond ) = @_;

   return deferred sub {
      my $resolve = shift;

      say ts(), " ===> polling_cond_wait: Start";

      my $result = eval { $cond->() };
      if ( $result ) {
         say ts(), " ===> polling_cond_wait: Condition is true";
         $resolve->();
      } else {
         say ts(), " ===> polling_cond_wait: Condition is false";

         delay( $sec )->then( sub {
            polling_cond_wait( $sec, $cond )->then( sub {
               $resolve->();
            } );
         } );
      }
   };
}

只剩下主要代码了。

use strict;
use warnings;
use feature qw( say );

use AE;
use AnyEvent;
use Promises backend => [ 'AnyEvent' ];
use Time::Piece qw( localtime );

$| = 1;

sub ts { "[" . localtime->strftime( "%Y-%m-%d %H:%M:%S" ) . "]" }

# ...

my $done = AE::cv;
my $inputs = 'starting';

{
   my $t; $t = AE::timer 5, 0, sub {
      $t = undef;
      say ts(), " ===> 5 s timer completed. Making `$inputs` next.";
      $inputs = 'next';
   };
}

{
   my $t; $t = AE::timer 15, 0, sub {
      $t = undef;
      say ts(), " ===> 15 s timer completed.";
   };
}

polling_cond_wait( 3, sub { $inputs eq 'next' } )->then( sub {
   say ts(), " ===> then";
   $done->send;
} );

$done->recv;

输出:

[2024-08-26 12:38:53] ===> polling_cond_wait: Starting.
[2024-08-26 12:38:53] ===> polling_cond_wait: Condition is false.
[2024-08-26 12:38:53] ===> delay: Delaying 3 s.
[2024-08-26 12:38:56] ===> delay: Delayed 3 s.
[2024-08-26 12:38:56] ===> polling_cond_wait: Starting.
[2024-08-26 12:38:56] ===> polling_cond_wait: Condition is false.
[2024-08-26 12:38:56] ===> delay: Delaying 3 s.
[2024-08-26 12:38:58] ===> 5 s timer completed. Making `starting` next.
[2024-08-26 12:38:59] ===> delay: Delayed 3 s.
[2024-08-26 12:38:59] ===> polling_cond_wait: Starting.
[2024-08-26 12:38:59] ===> polling_cond_wait: Condition is true.
[2024-08-26 12:38:59] ===> then

为什么要进行民意调查?

my $done = AE::cv;
my $promise = deferred;

{
   my $t; $t = AE::timer 5, 0, sub {
      $t = undef;
      say ts(), " ===> 5 s timer completed. Resolving promise.";
      $promise->resolve();
   };
}

{
   my $t; $t = AE::timer 15, 0, sub {
      $t = undef;
      say ts(), " ===> 15 s timer completed.";
   };
}

$promise->then( sub {
   say ts(), " ===> then";
   $done->send;
} );

$done->recv;
© www.soinside.com 2019 - 2024. All rights reserved.