++ed by:

2 PAUSE users

Felipe Gasper
and 2 contributors


Promise::XS - Fast promises in Perl


    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();

The following aggregator functions are exposed:

    # Resolves with a list of arrayrefs, one per promise.
    # Rejects with the results from the first rejected promise.
    my $all_p = Promise::XS::all( $promise1, $promise2, .. );

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

For compatibility with preexisting libraries, all() may also be called as collect().

The following also exist:

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

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

All of Promise::XS’s static functions may be exported at load time, e.g., use Promise::XS qw(deferred).


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.


Breaking changes in this interface are unlikely; however, the implementation is relatively untested since the fork. Your mileage may vary.


This library is built for compatibility with pre-existing Perl promise libraries. It thus exhibits some salient differences from how ECMAScript promises work:

  • Promise resolutions and rejections consist of lists, not single values.

  • Neither the resolve() method of deferred objects nor the resolved() convenience function define behavior when given a promise object.

  • 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 Promise::ES6 for an interface that imitates ECMAScript promises more closely.


This library, by default, uses no event loop. This is a perfectly 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.

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

  • AnyEvent:

  • IO::Async - note the need for an IO::Async::Loop instance as argument:

        Promise::XS::use_event('IO::Async', $loop_object);
  • 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.

REMINDER: There’s no reason why promises need an event loop; it just satisfies the Promises/A+ convention.


Any promise created while $Promise::XS::DETECT_MEMORY_LEAKS is truthy will throw a warning if it survives until global destruction.


You can re-bless a Promise::XS::Promise instance into a different class, and 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.


  • all() and race() should be implemented in XS, as should resolved() and rejected().


  • Interpreter-based threads may or may not work.

  • This module interacts badly with Perl’s fork() implementation on Windows. There may be a workaround possible, but none is implemented for now.


Besides AnyEvent::XSPromises and Promises, you may like Promise::ES6, which mimics ECMAScript’s “Promise” class 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.