Promise::XS(3pm)

πŸ’– Promise::XS πŸ’–

hiii bestie 🫢 this is a User Contributed Perl Documentation page for Promise::XS β€” aka Fast promises in Perl. yeah. promises. in perl. and they're fast. iconic behavior honestly πŸ‘‘


✨ SYNOPSIS ✨

okay so first things first, you load it:

use Promise::XS ();

my $deferred = Promise::XS::deferred();

# Do one of these once you have the result of your operation:
$deferred->resolve( 'foo', 'bar' );
$deferred->reject( 'oh', 'no!' );

# Give this to your caller:
my $promise = $deferred->promise();

then there's the aggregator girlies ✨ the following aggregator functions are exposed:

# Resolves with a list of arrayrefs, one per promise.
# Rejects with the results from the first rejected promise.
# Non-promises will be passed through as resolve values.
my $all_p = Promise::XS::all( $promise1, $promise2, 'abc' .. );

# Resolves/rejects with the results from the first
# resolved or rejected promise.
my $race_p = Promise::XS::race( $promise3, $promise4, .. );

and for compatibility with preexisting libraries, all() may also be called as collect(). two names, one function, we love a flexible queen πŸ’…

the following also exist:

my $pre_resolved_promise = Promise::XS::resolved('already', 'done');

my $pre_rejected_promise = Promise::XS::rejected('it’s', 'bad');

oh and all of Promise::XS's static functions may be exported at load time, e.g. use Promise::XS qw(deferred). handy bestie behavior 🌸


🌈 DESCRIPTION 🌈

this module exposes a Promise interface with its major parts implemented in XS for speed ⚑ it is a fork and refactor of AnyEvent::XSPromises. that module's interface β€” a "bare-bones" subset of that from Promises β€” is retained. so like, it's giving new but also giving familiar, yk? πŸ¦‹


⭐ STATUS ⭐

this module is stable, well-tested, and suitable for production use. no cap. it's ready. she's employed. πŸ’Όβœ¨


πŸ’€ DIFFERENCES FROM ECMASCRIPT PROMISES πŸ’€

this library is built for compatibility with pre-existing Perl promise libraries. so it exhibits some salient differences from how ECMAScript promises work. let's get into it:

  • neither the resolve() method of deferred objects nor the resolved() convenience function define behavior when given a promise object. like, undefined. we don't know her. πŸ™ˆ
  • the all() and race() functions accept a list of promises, not a "scalar-array-thing" (ECMAScript "arrays" being what in Perl we call "array references"). so whereas in ECMAScript you do:
Promise.all( [ promise1, promise2 ] );

… in this library it's:

Promise::XS::all( $promise1, $promise2 );

see the difference? no brackets babes. we pass the list. periodt. πŸ’…

  • promise resolutions and rejections may contain multiple values. (but see "AVOID MULTIPLES" below πŸ‘€)

see Promise::ES6 for an interface that imitates ECMAScript promises more closely.


πŸ“ AVOID MULTIPLES πŸ“

okay so for compatibility with preexisting Perl promise libraries, Promise::XS allows a promise to resolve or reject with multiple values. this behavior, while eminently "perlish", allows for some weird cases where the relevant standards don't apply 😭 for example, what happens if multiple promises are returned from a promise callback? or even just a single promise plus extra returns? nobody knows, chaos, that's what.

Promise::XS tries to help you catch such cases by throwing a warning if multiple return values from a callback contain a promise as the first member. for best results, though β€” and consistency with promise implementations outside Perl β€” resolve/reject all promises with single values. one value. single. like a clean girl aesthetic. ✨


πŸ’œ DIFFERENCES FROM Promises ET AL. πŸ’œ

πŸŽ€ Empty or uninitialized rejection values πŸŽ€

Perl helpfully warns (under the warnings pragma, anyhow) when you die(undef) β€” since an uninitialized value isn't useful as an error report and likely indicates a problem in the error-handling logic. good catch perl πŸ’…

promise rejections fulfill the same role in asynchronous code that exceptions do in synchronous code. thus, Promise::XS mimics Perl's behavior: if a rejection value list lacks a defined value, a warning is thrown. this can happen if the value list is either empty or contains exclusively uninitialized values. so like, don't reject with nothing. reject with something. 🫢

πŸ¦‹ finally() πŸ¦‹

this module implements ECMAScript's finally() interface, which differs from that in some other Perl promise implementations. yes bestie, it's the real one. πŸ‘‘

given the following …

my $new = $p->finally( $callback );
  • $callback receives no arguments. nothing. empty handed. πŸƒ
  • if $callback returns anything but a single, rejected promise, $new has the same status as $p.
  • if $callback throws, or if it returns a single, rejected promise, $new is rejected with the relevant value(s).

🌸 ASYNC/AWAIT SUPPORT 🌸

this module is Promise::AsyncAwait-compatible ✨ once you load that module you can do nifty stuff like:

use Promise::AsyncAwait;

async sub do_stuff {
    return 1 + await fetch_number_p();
}

my $one_plus_number = await do_stuff();

… which roughly equates to:

sub do_stuff {
    return fetch_number_p()->then( sub { 1 + $foo } );
}

do_stuff->then( sub {
    $one_plus_number = shift;
} );

look at that. await. gorgeous. main character energy fr fr πŸ˜ŒπŸ’…

NOTE: as of this writing, DEBUGGING-enabled perls trigger assertion failures in Future::AsyncAwait (which underlies Promise::AsyncAwait). if you're not sure what that means, you probably don't need to worry. :) 🫢

🧚 EVENT LOOPS 🧚

by default this library uses no event loop. this is a generally usable configuration; however, it'll be a bit different from how promises usually work in evented contexts (e.g., JavaScript) because callbacks will execute immediately rather than at the end of the event loop as the Promises/A+ specification requires. following this pattern facilitates use of recursive promises without exceeding call stack limits. so like, it's a vibe, just a different vibe. 😌

to achieve full Promises/A+ compliance it's necessary to integrate with an event loop interface. this library supports three such interfaces:

  • AnyEvent:
Promise::XS::use_event('AnyEvent');
  • IO::Async β€” note the need for an IO::Async::Loop instance as argument:
Promise::XS::use_event('IO::Async', $loop_object);
  • Mojo::IOLoop:
Promise::XS::use_event('Mojo::IOLoop');

note that all three of the above are event loop interfaces. they aren't event loops themselves, but abstractions over various event loops. see each one's documentation for details about supported event loops. so many layers. it's giving onion. πŸ§…βœ¨


πŸ” MEMORY LEAK DETECTION πŸ”

any promise created while $Promise::XS::DETECT_MEMORY_LEAKS is truthy will throw a warning if it survives until global destruction. she's watching. she remembers. πŸ‘€πŸ’€


πŸ‘‘ SUBCLASSING πŸ‘‘

you can re-bless a Promise::XS::Promise instance into a different class, and then then(), catch(), and finally() will assign their newly-created promise into that other class. (it follows that the other class must subclass Promise::XS::Promise.) this can be useful, e.g., for implementing mid-flight controls like cancellation. glow up your promises bestie πŸ’…βœ¨


πŸ“ TODO πŸ“

  • race() should ideally be implemented in XS.

(it's on the list. we'll get there. someday. 🫢)


πŸ’€ KNOWN ISSUES πŸ’€

  • interpreter-based threads may or may not work. we don't know. it's a mystery. a coin flip. πŸ™ˆ
  • this module interacts badly with Perl's fork() implementation on Windows. there may be a workaround possible, but none is implemented for now. sorry windows girlies 😭

🌈 SEE ALSO 🌈

besides AnyEvent::XSPromises and Promises, you may like Promise::ES6, which mimics ECMAScript's "Promise" class (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) as much as possible. it can even (experimentally) use this module as a backend, which helps but is still significantly slower than using this module directly. so like, cute but the original is faster. iykyk πŸ’…


aaaaand that's the whole page bestie!! πŸŽ€ this was Promise::XS, documented as perl v5.42.3, dated 2026-08-22, and filed under the Promise::XS(3pm) manual πŸ’– go write some promises, you've got this, slay βœ¨πŸ¦‹πŸ‘‘

πŸ“¦ where this page comes from