my enum PromiseStatus (:Planned(0), :Kept(1), :Broken(2));
class Promise {}

Promise 用于处理可能尚未完成的计算结果。它允许用户在计算完成后执行代码(使用 then 方法),在时间延迟后执行(使用 in),组合承诺和等待结果。

my $p = Promise.start({ sleep 242});
$p.then({ say .result });   # will print 42 once the block finished 
say $p.status;              # OUTPUT: «Planned␤» 
$p.result;                  # waits for the computation to finish 
say $p.status;              # OUTPUT: «Kept␤»

使用承诺有两种典型情况。第一种是在类型对象上使用工厂方法(startinatanyofallofkeptbroken);这些方法将确保承诺会自动为您保留或中断,并且您不能在这些承诺上自己调用 breakkeep

第二种是使用 Promise.new 自己创建承诺。如果您想确保只有您的代码可以保留或中断承诺,可以使用 vow 方法获取唯一句柄,并在其上调用 keepbreak

sub async-get-with-promise($user-agent$url{
    my $p = Promise.new;
    my $v = $p.vow;
 
    # do an asynchronous call on a fictive user agent, 
    # and return the promise: 
    $user-agent.async-get($url,
            on-error => -> $error {
                $v.break($error);
            },
            on-success => -> $response {
                $v.keep($response);
            }
    );
    return $p;
}

可以在 并发页面 中找到更多示例。

方法§

方法 start§

method start(Promise:U: &code:$scheduler = $*SCHEDULER --> Promise:D)

创建一个新的 Promise,运行给定的代码对象。当代码正常终止时,承诺将被保留,如果它抛出异常,则会被中断。可以使用 result 方法检查返回值或异常。

处理此承诺的调度程序可以作为命名参数传递。

还有一个语句前缀 start,它为此方法提供了语法糖

# these two are equivalent: 
my $p1 = Promise.start({ ;#`( do something here ) });
my $p2 = start { ;#`( do something here ) };

从该语言的 6.d 版本开始,在 sink 上下文中使用的 start 语句前缀将自动附加异常处理程序。如果给定代码中发生异常,它将被打印,然后程序将退出,就像在没有任何 start 语句前缀参与的情况下抛出异常一样。

use v6.c;
start { die }sleep ⅓; say "hello"# OUTPUT: «hello␤» 
use v6.d;
start { die }sleep ⅓; say "hello";
# OUTPUT: 
# Unhandled exception in code scheduled on thread 4 
# Died 
#     in block  at -e line 1 

如果您希望避免此行为,请在非 sink 上下文中使用 start 或自己捕获异常

# Don't sink it: 
my $ = start { die }sleep ⅓; say "hello"# OUTPUT: «hello␤» 
 
# Catch yourself: 
start { dieCATCH { default { say "caught" } } };
sleep ⅓;
say "hello";
# OUTPUT: «caught␤hello␤» 

此行为仅以语法方式存在,通过对 sink 上下文中 start 块创建的 Promise 对象使用备用的 .sink 方法,因此简单地沉没由其他方式创建的 Promise 对象不会触发此行为。

方法 in§

method in(Promise:U: $seconds:$scheduler = $*SCHEDULER --> Promise:D)

创建一个新的 Promise,该 Promise 将在 $seconds 秒或更长时间后保留。

my $proc = Proc::Async.new('raku''-e''sleep 10; warn "end"');
 
my $result = await Promise.anyof(
    my $promise = $proc.start,  # may or may not work in time 
    Promise.in(5).then: {       # fires after 5 seconds no matter what 
        unless $promise {       # don't do anything if we were successful 
            note 'timeout';
            $proc.kill;
        }
    }
).then: { $promise.result }
# OUTPUT: «timeout␤»

$seconds 可以是小数或负数。负值被视为 0(即立即 保留 返回的 Promise)。

请注意,使用 react 和 whenever 块 通常可以更清楚地处理此类情况。

方法 at§

method at(Promise:U: $at:$scheduler = $*SCHEDULER --> Promise:D)

创建一个新的 Promise,该 Promise 将在给定的时间(以 Instant 或等效的 Numeric 表示)或在该时间之后尽快保持。

my $p = Promise.at(now + 2).then({ say "2 seconds later" });
# do other stuff here 
 
await $p;   # wait here until the 2 seconds are over

如果给定的时间在过去,它将被视为 现在(即立即 保持 返回的 Promise)。

请注意,使用 react 和 whenever 块 通常可以更清楚地处理此类情况。

方法 kept§

multi method kept(Promise:U: \result = True --> Promise:D)

返回一个新的 promise,该 promise 已保持,要么具有给定的值,要么具有默认值 True

方法 broken§

multi method broken(Promise:U: --> Promise:D)
multi method broken(Promise:U: \exception --> Promise:D)

返回一个新的 promise,该 promise 已中断,要么具有给定的值,要么具有默认值 X::AdHoc.new(payload => "Died")

方法 allof§

method allof(Promise:U: *@promises --> Promise:D)

返回一个新的 promise,该 promise 将在作为参数传递的所有 promise 保持或中断时保持。单个 Promise 的结果不会反映在返回的 promise 的结果中:它只是表明所有 promise 已以某种方式完成。如果单个 promise 的结果很重要,则应在 allof promise 保持后对其进行检查。

在以下示例中,请求中断 promise 的 result 将导致抛出原始异常。(您可能需要运行它几次才能看到异常。)

my @promises;
for 1..5 -> $t {
    push @promisesstart {
        sleep $t;
    };
}
my $all-done = Promise.allof(@promises);
await $all-done;
@promises>>.result;
say "Promises kept so we get to live another day!";

方法 anyof§

method anyof(Promise:U: *@promises --> Promise:D)

返回一个新的 promise,该 promise 将在作为参数传递的任何 promise 保持或中断后立即保持。已完成 Promise 的结果不会反映在返回的 promise 的结果中,后者始终保持。

您可以使用此方法最多等待 promise 几秒钟

my $timeout = 5;
await Promise.anyof(
    Promise.in($timeout),
    start {
        # do a potentially long-running calculation here 
    },
);

方法 then§

method then(Promise:D: &code)

计划在调用者保持或中断后运行一段代码,并为该计算返回一个新的 promise。换句话说,创建一个链式 promise。Promise 作为参数传递给 &code

# Use code only 
my $timer = Promise.in(2);
my $after = $timer.then({ say '2 seconds are over!''result' });
say $after.result;
# OUTPUT: «2 seconds are over␤result␤» 
 
# Interact with original Promise 
my $after = Promise.in(2).then(-> $p { say $p.statussay '2 seconds are over!''result' });
say $after.result;
# OUTPUT: «Kept␤2 seconds are over␤result␤»

方法 keep§

multi method keep(Promise:D: \result = True)

保持一个 promise,可以选择设置结果。如果未传递结果,则结果将为 True

如果已发誓,则抛出类型为 X::Promise::Vowed 的异常。有关更多信息,请参见方法 vow

my $p = Promise.new;
 
if Bool.pick {
    $p.keep;
}
else {
     $p.break;
}

方法 break§

multi method break(Promise:D: \cause = False)

中断一个 promise,可以选择设置原因。如果未传递原因,则原因将为 False

如果已发誓,则抛出类型为 X::Promise::Vowed 的异常。有关更多信息,请参见方法 vow

my $p = Promise.new;
 
$p.break('sorry');
say $p.status;          # OUTPUT: «Broken␤» 
say $p.cause;           # OUTPUT: «sorry␤»

方法 result§

method result(Promise:D:)

等待 promise 保持或中断。如果保持,则返回结果;否则,将结果作为异常抛出。

方法 cause§

method cause(Promise:D:)

如果 promise 中断,则返回结果(或异常)。否则,抛出类型为 X::Promise::CauseOnlyValidOnBroken 的异常。

方法 Bool§

multi method Bool(Promise:D:)

对于已兑现或已违背的承诺,返回 True,对于状态为 Planned 的承诺,返回 False

方法 status§

method status(Promise:D --> PromiseStatus)

返回承诺的当前状态:KeptBrokenPlanned

say "promise got Kept" if $promise.status ~~ Kept;

方法 scheduler§

method scheduler(Promise:D:)

返回管理承诺的调度程序。

方法 vow§

my class Vow {
    has Promise $.promise;
    method keep() { ... }
    method break() { ... }
}
method vow(Promise:D: --> Vow:D)

返回一个对象,该对象拥有兑现或违背承诺的唯一权限。对已获取誓言的承诺调用 keepbreak 会抛出类型为 X::Promise::Vowed 的异常。

my $p   = Promise.new;
my $vow = $p.vow;
$vow.keep($p);
say $p.status;          # OUTPUT: «Kept␤»

方法 Supply§

method Supply(Promise:D:)

返回一个 Supply,该 Supply 将发出兑现 Promiseresult,或在 Promise 被违背时发出带有 causequit

子例程 await§

multi await(Promise:D --> Promise)
multi await(*@ --> Array)

等待一个或多个承诺全部兑现,然后返回其值。还适用于 Channel。任何违背的承诺都会重新抛出其异常。如果传递了一个列表,它将返回一个列表,其中包含依次等待每个项目的结果。

类型图§

Promise 的类型关系
raku-type-graph Promise Promise Any Any Promise->Any Mu Mu Any->Mu

展开上面的图表