Code Monkey home page Code Monkey logo

promise's Introduction

ReactPHP Logo

Event-driven, non-blocking I/O with PHP.

Build Status

ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of which it provides low-level utilities, such as: Streams abstraction, async DNS resolver, network client/server, HTTP client/server and interaction with processes. Third-party libraries can use these components to create async network clients/servers and more.

<?php

// $ composer require react/http react/socket # install example using Composer
// $ php example.php # run example on command line, requires no additional web server

require __DIR__ . '/vendor/autoload.php';

$server = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
    return React\Http\Message\Response::plaintext(
        "Hello World!\n"
    );
});

$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$server->listen($socket);

echo "Server running at http://127.0.0.1:8080" . PHP_EOL;

This simple web server written in ReactPHP responds with "Hello World!" for every request.

ReactPHP is production ready and battle-tested with millions of installations from all kinds of projects around the world. Its event-driven architecture makes it a perfect fit for efficient network servers and clients handling hundreds or thousands of concurrent connections, long-running applications and many other forms of cooperative multitasking with non-blocking I/O operations. What makes ReactPHP special is its vivid ecosystem with hundreds of third-party libraries allowing you to integrate with many existing systems, such as common network services, database systems and other third-party APIs.

  • Production ready and battle-tested.
  • Rock-solid with stable long-term support (LTS) releases.
  • Requires no extensions and runs on any platform - no excuses!
  • Takes advantage of optional extensions to get better performance when available.
  • Highly recommends latest version of PHP 7+ for best performance and support.
  • Supports legacy PHP 5.3+ and HHVM for maximum compatibility.
  • Well designed and reusable components.
  • Decoupled parts so they can be replaced by alternate implementations.
  • Carefully tested (unit & functional).
  • Promotes standard PSRs where possible for maximum interoperability.
  • Aims to be technology neutral, so you can use your preferred application stack.
  • Small core team of professionals supported by large network of outside contributors.

ReactPHP is non-blocking by default. Use workers for blocking I/O. The event loop is based on the reactor pattern (hence the name) and strongly inspired by libraries such as EventMachine (Ruby), Twisted (Python) and Node.js (V8).

This repository you're currently looking at is mostly used as a meta repository to discuss and plan all things @ReactPHP. See the individual components linked below for more details about each component, its documentation and source code.

Core Components

Network Components

Utility Components

Built with ReactPHP

  • Thruway PHP Client and Router Library for Autobahn and WAMP (Web Application Messaging Protocol) for Real-Time Application Messaging voryx/Thruway

  • PPM - PHP Process Manager PPM is a process manager, supercharger and load balancer for modern PHP applications. php-pm/php-pm

  • php-ar-drone 🚁 Port of node-ar-drone which allows user to control a Parrot AR Drone over PHP jolicode/php-ar-drone

  • Ratchet Asynchronous WebSocket server ratchetphp/Ratchet

  • Predis\Async Asynchronous PHP client library for Redis built on top of ReactPHP nrk/predis-async

  • clue/redis-server A Redis server implementation in pure PHP clue/redis-server

And many more on our wiki page »

Articles

  • Sergey Zhuk A series of articles covering ReactPHP: from the basics to the real application examples. sergeyzhuk.me

  • Cees-Jan Kiewiet Blog series about several ReactPHP components and how they work. blog.wyrihaximus.net

  • Loïc Faugeron Super Speed Symfony - ReactPHP. gnugat.github.io

  • Marc J. Schmidt Bring High Performance Into Your PHP App (with ReactPHP). marcjschmidt.de

  • Marc Morera When ReactPHP meet Symfony medium.com/@apisearch

Talks

Getting started

ReactPHP consists of a set of individual components. This means that instead of installing something like a "ReactPHP framework", you actually pick only the components that you need.

This project follows SemVer for all its stable components. The recommended way to install these components is through Composer. New to Composer?

For example, this may look something like this:

# recommended install: pick required components
composer require react/event-loop react/http

As an alternative, we also provide a meta package that will install all stable components at once. Installing this is only recommended for quick prototyping, as the list of stable components may change over time. This meta package can be installed like this:

# quick protoyping only: install all stable components
composer require react/react:^1.4

For more details, check out ReactPHP's homepage for quickstart examples and usage details.

See also the combined changelog for all ReactPHP components for details about version upgrades.

Support

Do you have a question and need help with ReactPHP? Don't worry, we're here to help!

As a first step, check the elaborate documentation that comes with each component (see links to individual documentation for each component above). If you find your question is not answered within the documentation, there's a fair chance that it may be relevant to more people. Please do not hesitate to file your question as an issue in the relevant component so others can also participate.

You can also check out our official Gitter chat room. Most of the people involved in this project are available in this chat room, so many questions get answered in a few minutes to some hours. We also use this chat room to announce all new releases and ongoing development efforts, so consider staying in this chat room for a little longer.

Also follow @reactphp on Twitter for updates. We use this mostly for noteworthy, bigger updates and to keep the community updated about ongoing development efforts. You can always use the #reactphp hashtag if you have anything to share!

We're a very open project and we prefer public communication whenever possible, so that more people can participate and help getting the best solutions available. At the same time, we realize that some things are better addressed in private. Whether you just want to say thank you, want to report a security issue or want to help sponsor a certain feature development, you can reach out to the core team in private by sending an email to [email protected]. Please keep in mind that we're a small team of volunteers and do our best to support anybody reaching out.

Do you want to support ReactPHP? Awesome! Let's start with letting the the world know why you think ReactPHP is awesome and try to help others getting on board! Send a tweet, write a blog post, give a talk at your local user group or conference or even write a book. There are many ways you can help. You can always reach out to us in private and help others in our support channels. Thank you!

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

composer install

To run the test suite, go to the project root and run:

vendor/bin/phpunit

The test suite also contains a number of functional integration tests that rely on a stable internet connection. Due to the vast number of integration tests, these are skipped by default during CI runs. If you also do not want to run these, they can simply be skipped like this:

vendor/bin/phpunit --exclude-group internet

License

MIT, see LICENSE.

promise's People

Contributors

bzikarsky avatar carusogabriel avatar cboden avatar cdosoftei avatar clue avatar danielecr avatar igorw avatar joshdifabio avatar jsor avatar kubo2 avatar miguilimzero avatar mtdowling avatar nawarian avatar nhedger avatar ondrejmirtes avatar reedy avatar s-bronstein avatar seregazhuk avatar simonfrings avatar sqko avatar woodongwong avatar wyrihaximus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

promise's Issues

Resolve before returning?

Here is a contrived example of a promise that is resolved before being used.

function do_something() {
    $deferred = new Deferred();
    $deferred->resolve(true);
    return $deferred->promise();
}

do_something()->then(function() {
    // This is never called, because the resolution has occurred before the call to then.
});

Can anyone suggest a way of using this code in the current release? If not, does anyone have any suggestions to the implementation? My thoughts are to check if the promise is resolved within the then call, and if so, call the onFulfilled function automatically.

[RFC] Deprecate promise progress API

This ticket serves as a basis for discussing deprecating the promise progress API.
This has come up quite a few times.

As a first step, this ticket aims to only deprecate the existing functionality and update the documentation accordingly. At a later stage, we should consider dropping the functionality altogether (BC break ahead).

Opening this ticket as an RFC and for the reference.

Perhaps there is an iterative approach instead of recursive?

This library currently uses recursion for promise chain resolution. Using a promise and chaining off of the promise potentially forever, will cause a stack overflow due to deep recursion.

Here's a really contrived example:

$d = new \React\Promise\Deferred();
$p = $d->promise();
$f = function ($x) {
    echo xdebug_get_stack_depth() . ', ';
    return $x;
};

$last = $p;
for ($i = 0; $i < 1000; $i++) {
    $last = $last->then($f);
}

$d->resolve('test');

Running this code will show that the stack depth grows significantly for each promise resolution:

9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, 84, 89, 94, PHP Fatal error:  Maximum function nesting level of '100' reached, aborting!

I don't usually use XDebug's default nesting limit of 100, but this illustrates the point that this library provides a recursive solution. I wonder if there is a way to implement promise resolution iteratively.

@jsor Have you ever attempted this or considered an iterative approach? It seems like some kind of directed acyclic graph structure that branches off of the deferred() would allow for an iterative approach.

How LazyPromise is supposed to be used with Deferred?

I am performing an RPC call over MQ. and I'd like to return the control to the code that invoked my method. The $reply->receive() call must be postponed as long as possible. It is blokcing operation and it returns the result. I cannot call $deferred->resolve immidiatly so I am thinking of doing something with LazyPromise. Something like this:

<?php

public function __invoke(Message $message, Deferred $deferred = null):Promise
{
    // do some stuff which results in $reply var. 

        return new LazyPromise(function() use ($deferred, $reply) {
            try {
                $value = JSON::decode($reply->receive($this->replyTimeout)->getBody());

                $deferred->resolve($value);
            } catch (TimeoutException $e) {
                $deferred->reject($e->getMessage());
            }

            return $deferred->promise();
        });
    }

Is this the right way to go? Is there a better solution?

Chaining question

I have an array of items of variable length where I want to process each item by the same function after the previous promise has resolved. I just can't figure out how to code it, I keep ending up thinking in loops while I guess I shouldn't:

$items = array(...variable number of items in here...);

$this->doSomethingAsyncAndReturnAPromise($firstItem)->then(
    function () {
        $this->doSomethingAsyncAndReturnAPromise($secondItem)->then(     
            ... and so on for all the remaining $items
        );
    }
);

Can anyone point me in the right direction how to do this?

Question

Are the following codes same?

$promise= $deferred->promise()
    ->then(function () {
          // Logic codes
    })
    ->then(function () {
          // Logic codes
    })
    ->then(function () {
          // Logic codes
    });

And

$promise= $deferred->promise()
    ->then(function () {
          // Logic codes
    });
$promise->then(function () {
          // Logic codes
    });
$promise->then(function () {
          // Logic codes
    });

Catch \Throwable instead of \Exception in PHP7

Type errors are not caught by the React Promise implementation in PHP7. It's fairly trivial to implement catch-all for PHP7 and PHP5 without breaking BC.

try {
  // call a success/error/progress handler
} catch (\Throwable $e) {
  // handle $e
} catch (\Exception $e) {
  // handle $e
}

Synchrony of promises

Hello everyone,
to begin with I am big fan of React project in general, its very promising, congratulation guys! I am sorry for writing a question here, but since this project is hard to find in google at all, waiting for answer in stackoverflow or similar service would take me forever.
I recently discovered promises and was very glad that someone implemented them in PHP since this is a feature I need in my recent project. However I can't understand one thing about react implementation of them and I hope you can help me with that. I read some older issues and have seen that you guys don't want to incorporate ReactLoop into promises, but I can't understand why. Since PHP by default is synchronous and one-threaded, using promises without loop results in synchronous execution of all callbacks in quite atomic-way which negates purpose of promises and is against Promise/A+ specification that says calling callbacks should be done asynchronously. Is there a technical problem you have difficulty with right know for proper implementation or did I understand the idea wrongly?

oop(s)

I don't understand the point of having namespaces and oop if we need to require a file having functions defined globally like in functions.php

<?php

if (!function_exists('React\Promise\resolve')) {
    require __DIR__.'/functions.php';
}

Cancellation of promise collections

What is the recommended way to cancel promise collections?

This library provides several promise collection primitives, which all have valid use cases.

One might assume the following is the way to go:

$promises = array(
    accessSomeRemoteResource(),
    accessSomeRemoteResource(),
    accessSomeRemoteResource()
);

$promise = \React\Promise\all($promises);

// what does this do?
$promise->cancel();

How does this cope with cancellation support?

This is currently not implemented, i.e. calling cancel() currently has no effect.

Should we consider adding this?

Also, if yes, how could cancellation support work for the other primitives?

How i can throw Exception from onRejected callback?

my code:

RatchetClient\connect("ws://{$this->host}:{$this->port}")->then(function(WebSocket $conn) use ($event, $data) {
    $conn->on('message', function($msg) use ($conn) {
        $conn->close();
    });

    $conn->send(json_encode(['event' => $event, 'data' => $data]));
}, function ($e) {
    // this exception never called, somebody catch it
    throw new RuntimeException("Could not connect: {$e->getMessage()}\n");
});

If my websocket server not running - nothing happen, i want see exception and stop execution.
How i can throw Exception from onRejected callback?

guzzle/promises

How can I convert guzzle/promises to reactphp/promise ?
As there is no done() method for guzzle/promises , I want to convert it to reactphp/promise

// $guzzlePromise is an instance of GuzzleHttp\Promise\Promise and is a result of third party library
$reactPromise = convert($guzzlePromise);

Mark promise progress / notify() as deprecated for Promise v2

The promise progress / notify() API is deprecated and has been removed with the upcoming Promise v3 release (see #32). There's currently no schedule as to when this version is going to be released.

The current documentation for Promise v2 should include a deprecation notice to discourage people from relying on this API.

Validate array argument for promise-array related functions

Reject all() / race() / any() / some() / map() / reduce() when called with a non-array.

all(null)
    ->otherwise(function(\InvalidArgumentException $e) {
        assertEquals('Expecting an array or a promise which resolves to an array, got NULL instead.' , $exception->getMessage());
    });

Callback wrapper ?

Hello, i writing code using reactphp promise library. I need to call some method and if promise failure then call this method again and again.

First time i written next code:

$instance = new SomeObject();
$onSuccess = function(){
    // do some useful things
};
$onFailure = function() use($instance, $onSuccess, &$onFailure){
    // retry function call
    $instance->method()->then($onSuccess, $onFailure);
};
$instance->method()->then($onSuccess, $onFailure);

This code have 2 problems:

  1. "$instance->method()->then()" is copypaste. When method has params i need to copypaste more and pass through "use" too much params..
  2. If use this way, then i can write buggy code if accidentally reuse $onFailure because it passed via reference.

To avoid this issues i had re-written my code:

class CallbackWrapper{
    public $invoke;
    public $onSuccess;
    public $onFailure;

    public function invoke(){
        call_user_func($this->invoke);
    }
}

$instance = new SomeObject();

$callback = new CallbackWrapper();
$callback->onSuccess = function(){
    // do some useful things
};
$callback->onFailure = function() use($callback){
    $callback->invoke();
};
$callback->invoke = function() use($instance, $callback){
    $instance->method()->then($callback->onSuccess, $callback->onFailure);
};
$callback->invoke();

I see no issues with this code, but have a practical trouble - i need this helper in the majority of projects that uses promises. So maybe it makes sense to include such a helper to the promise library? Or may be i miss something and promise library has another ways to do it?

Sorry for my clumsy English.

Difficulty testing with exception design

Contrary to #46 perhaps we shouldn't be catching \Exception in function then() at all.

Just spent a bit of time debugging why I couldn't unit test promises.

$promise->then(function($results) {
    $this->assertCount(2, $results);
});

This was not failing the test when count was not correct. Finally figured out that phpunit is actually throwing an exception when the assert fails (I didn't know this), and promise->then() uses a try/catch around the resolve call (I also didn't know this.)

I feel like the try/catch from within the then() function probably makes things more difficult than it helps.

Granted, my workaround is to use(&$rowcount), but it still seems throwing an exception from within a resolve, ought to bounce out to the caller.

$rowcount = false;
$promise->then(function($results) use (&$rowcount) {
    $rowcount = count($results);
});
$this->assertEquals(2, $rowcount);

\React\Promise\all not preserving array key order

Hi I ran into an strange issue and am wondering is this intended behavior?

Basically I'm expecting that for the included code the output would be:

.Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

But instead I'm getting the array keys unordered:

.Array
(
    [0] => 1
    [2] => 3
    [1] => 2
)

Which causes problems for example when json_encoding (PHP thinks it should be encoded as an object not an array).

Code to reproduce:

$loop = Factory::create();

$testData = [
    new Promise(
        function ($resolve) use ($loop) {
            $loop->nextTick(
                function () use ($resolve) {
                    $resolve(1);
                }
            );
        }
    ),
    new Promise(
        function ($resolve) use ($loop) {
            $loop->nextTick(
                function () use ($resolve, $loop) {
                    \React\Promise\resolve()->then( function() use ($resolve, $loop) {
                        $loop->nextTick(function () use ($resolve) {
                            $resolve(2);
                        });
                    });
                }
            );
        }
    ),
    new Promise(
        function ($resolve) use ($loop) {
            $loop->nextTick(
                function () use ($resolve) {
                    $resolve(3);
                }
            );
        }
    )
];


\React\Promise\all($testData)->then(function ($result) {
    print_r($result);
});

$loop->run();

Thanks!

Enforce \Exception instances as rejection values

This also removes support for rejecting with a Promise instance.

Decide whether the rejection value is still an optional argument and can be null. Enforcing an argument is more inline with throw (you can't throw null) and let's us remove UnhandledRejectionException.

Guarantee future-turn resolutions

At the moment, we're not guaranteeing future-turn resolutions (which basically means, that callbacks should always be called asynchronously, read this).

All major JavaScript libs guarantee that (when.js does not at the moment, but will in their next major release).

We have 2 options.

  1. We do not guarantee future-turn resolutions

    We keep it simple. Methods in When can stay static and creating Deferred's is as simple as doing $d = new Deferred. We should note that in the docs, so that developers are aware that there is no guarantee about if a promise will resolve asynchronously or synchronously.

  2. We do guarantee future-turn resolutions

    This would couple React/Promise to the EventLoop (or at least to some kind of QueueProcessor for which we have an EventLoop adapter). We would have to make When non-static (and require the EventLoop or a QueueProcessor in the constructor which will be passed to Deferredinstances) and it will most probably become some kind of global entry point for creating promises and deferreds.

Cancellable promises.

Hey guys, I noticed that there's an implementation of cancellable promises in a branch. Is that something that is desired in v2? Are there any hurdles that need to be overcome?

Examples for writing unit tests?

I'm trying to write a unit test for code that uses Promises. I looked at the tests in this project, but I can't figure out what's happening, I was expecting to see some reference to an event loop, that I can block on, but it seems like no such things are happening?

How can I make PHPUnit block/wait until my promises resolve? For example, see the following test:

    public function testPromises() {
        $promise = new Promise(function() {
            return ['hello' => 'world'];
        });
        $promise->then(function($result) {
            $this->assertArrayHasKey('hello', $result);
        });
    }

This fails with the error "This test did not perform any assertions", which is expected, since nothing is blocking execution until the promise resolves.

How can I block PHPUnit until my promises resolve?

Cannot redeclare React\Promise\resolve()

Hi,

we stumbled over this issue today:

PHP Fatal error:  Cannot redeclare React\Promise\resolve() (previously declared in /root/.composer/vendor/react/promise/src/functions.php:5) in /app/vendor/react/promise/src/React/Promise/functions.php on line 12
PHP Fatal error:  Cannot redeclare React\Promise\resolve() (previously declared in /root/.composer/vendor/react/promise/src/functions.php:5) in /app/vendor/react/promise/src/React/Promise/functions.php on line 12
[...]

We have a composer packages installed globally and per project which both depend on react/promise.

I think the composer autoloader always loads the file specified here which looks to me like the source of the error.

I don't know if composer should handle that...

You could wrap the definitions in a function_exists() call if you have to use the legacy files autoloading.

Syntax error

Parse error: syntax error, unexpected '[' in /home/seewhaty/public_html/site/vendor/react/promise/src/functions.php on line 75

Missing example code

Hi!

I'm trying to evaluate react/promise as alternative to guzzlehttp/promise, but I can't seem to find a way to reap a promise, i.e. wait for it to be resolved and get at the according result. All I can do is to tell it what to do with the result (using then() or done()), but that just gives me another promise which is just as useful as the one I had.

I'm sure it can be done, but it's not obvious, or at least not obvious to someone who doesn't have certain background knowledge. I'd be happy if you just added a few examples that people can actually execute or use as base for their own development.

Thanks!

Uli

Merge interfaces

Merge PromiseInterface, ExtendedPromiseInterface and CancellablePromiseInterface into a single interface (PromiseInterface).

callable param can not be null in the fastcgi environment

$defer = new React\Promise\Deferred();
$defer->promise();   

I found that this code can run normally in the cli environment, but it will trigger this error in the fast-cgi(php-fpm) environment.
php version: 5.4.41
error message:

PHP Catchable fatal error:  Argument 1 passed to React\Promise\Promise::__construct() must be callable, null given, called in vendor/react/promise/src/Deferred.php on line 25 and defined in vendor/react/promise/src/Promise.php on line 16 

I guess that this is an bug of php-fpm.

Creating Promise out of an event emitter ?

Not sure if this is the right project for this, as this depends of both Promise and Evenement.

Having heavily worked with reactphp recently, I ended up creating Promises out of EventEmitters a lot. The typical piece of code looks like this:

$deferred = new Deferred();

$emitter->once('data', [$deferred, 'resolve']);
$emitter->once('error', [$deferred, 'reject']);

return $deferred->promise()
  ->always(function() use ($deferred, $emitter) {
    // Remove listener to avoid leaking memory
    $emitter->removeListener('data', [$deferred, 'resolve']);
    $emitter->removeListener('error', [$deferred, 'reject']);
  });

And this doesn't even handle cancellations.

Wouldn't some kind of EventListenerPromise be useful in the Promise library ?

Detecting unhandled rejections

When using promises, there are a good chance that some code will forget to handle rejections/exceptions in a promise chain. This has the result of effectively hidding any rejection/exception that occurred during the execution of a promise's callback, which is dangerous and can lead to undetected bugs.

What makes this worse is that is suffices of a single error/forget in a promise chain to hide all exceptions thrown anywhere in the chain, including errors in react-php: reactphp/http-client#31, reactphp/dns#26.

It's super easy to not handle a rejection: if a promise chain is ended by anything except done(), any errors in the chain will be unhandled and potentially hidden:

$promise->always(function() {
    doSomething();
});

This example is quite obvious: any exception thrown in doSomething() is caught and hidden from the user.

Other example from react/http-client:

$promise->then(function () {
    // ok
}, function ($err) {
    $this->emit('error', $err);
    // in the 'error' callback:
    $this->retry();
})->then(function () {
    doSomething();
});

This one is less obvious. In this example, any exception thrown in retry() is caught by the promise and effectively hidden from the user.

Some promise implementations are trying to detect unhandled rejections, and log them: http://bluebirdjs.com/docs/api/error-management-configuration.html

It is possible to do so in react/promise too. For that, we would have to simply watch when promises are instantiated, handled, and destructed. If a non-handled promise is destructed, it means that an unhandled rejection occurred.

Here is a PoC adding tracing functionality to promises: arnaud-lb@90e6e35

And here is a PoC tracer that detects unhandled rejections: https://gist.github.com/arnaud-lb/a2a5a5480bbd80013f756ff968282936

This can be used like this:

<?php

$tracer = new UnhandledRejectionTracer(function ($info) {
    var_dump("unhandled promise", $info);
});
RejectedPromise::setTracer($tracer);
FulfilledPromise::setTracer($tracer);

register_shutdown_function(function () use ($tracer) {
    // handle non-destructed promises
    foreach ($tracer->getRemainingPromises() as $info) {
        var_dump("unhandled promise", $info);
    }
});

This immediately discovered a few bugs in my code. I'm using this since a few months already, and this prevents the introduction of new bugs.

[RFC] Change cancellation semantics

This issue serves a basis for discussing changing the cancellation semantics. The change is best described by quoting the bluebird docs:

The new cancellation has "don't care" semantics while the old cancellation had abort semantics. Cancelling a promise simply means that its handler callbacks will not be called.

At the moment, there is no predictable behavior when cancelling promises because the producer of the root promise decides what the behaviour is (eg. rejecting the promises).

Changing the semantics would also allow for internal performance and memory optimizations because registered handlers could be discarded (see #55).

New Promise constructor and resolver function signature:

$promise = new Promise(function(callable $resolve, callable $reject, callable $onCancel) {
    $onCancel(function() {
        // Do something on cancellation
    });
});

Note, that the second $canceller argument has been removed from the Promise constructor. Everything is now handled inside the resolver function.
Advantage: Resolution and cancellation share the same scope and multiple cancellation callbacks can be registered via $onCancel.
Possible problem: The third $onCancel argument has been the $notify callback in 2.x. This might lead to subtle bugs when upgrading from 2.x to 3.x.

Handlers

Handlers registered with always() are called even if the promise is cancelled as it is the finally counterpart from try/catch. No other types of handlers (registered with then(), otherwise() etc.) will be called in case of cancellation.

Consuming cancelled promises will return a promise that is rejected with a CancellationException as the rejection reason.

React\Promise\FulfilledPromise Object

Hi,

I create a promise like this:

public function callService($condition) {
        $deferred = new \React\Promise\Deferred();

        $this->callApi($condition, function($result) use ($deferred) {
            if (empty($result)) {
                $deferred->reject(new \Exception('No prices available!'));
            } else {
                $deferred->resolve($result);
            }
        });

        return $deferred->promise();
}

And in the return of the promise:

return $this->callService($condition)
    ->then(
        function($prices) {   
                return $prices;
        },
        function(\Exception $e) {
                return $e->getMessage();
        }
    );

It return a FulfilledPromise with private value. How can I return only the value of prices?

Thanks for advance.

exception in promise

How can l throw an uncaught exception onRejected?
I try then and done but no difference.

$promise->then(null, function (){
    throw new Exception;
});
$promise->done(null, function (){
    throw new Exception;
});

pthread compatibility

Hi,

I was trying to use react/promise with pthread and started a ticket in the pthread repo,
krakjoe/pthreads#283

Can you confirm if pthread support for react is being worked on?

Thanks,
Shawn

done() exceptions bubble up into the wrong place

done() callbacks aren't supposed to throw exceptions, but they might, because bugs. If this happens, the exception just bubbles up into the reject() call where it shouldn't end up, because reject() isn't supposed to throw exceptions. The resolution and consumption parts should be strictly separated and not affect each other. One solution is to use trigger_error($exception, E_USER_ERROR); instead.

Additionally, an error handler could be used similar to the one proposed in async-interop to allow users to catch and log these errors but continue execution.

The following code snippet demonstrates reject() throwing while it's not supposed to throw.

<?php

require __DIR__ . "/vendor/autoload.php";

$deferred = new React\Promise\Deferred;

$deferred->promise()->done(function ($value) { }, function ($reason) {
    throw new Exception;
});

try {
    $deferred->reject("foobar");
} catch (Exception $e) {
    print "Uhm... reject isn't supposed to throw." . PHP_EOL;
}

Queue broken when throwing from `done()` (dev-master only)

In case there's something enqueued that throws, the queue is never drained again if it wasn't empty after throwing.

<?php

require __DIR__ . "/vendor/autoload.php";

use React\Promise\FulfilledPromise;
use React\Promise\RejectedPromise;

$promiseA = new RejectedPromise(new RuntimeException("A"));

try {
    $promiseA->done(null, function ($e) {
        $promiseB = new RejectedPromise(new RuntimeException("B"));
        $promiseB->then(null, function () {
            print "OK" . PHP_EOL;
        });

        throw $e;
    });
} catch (Throwable $e) {
    // exception caught
}

$promiseC = new FulfilledPromise("C");
$promiseC->then(function () {
    // never executed

    print "C" . PHP_EOL;
});

print " -- END -- " . PHP_EOL;

It's a specially crafted example, not sure whether it will ever happen accidentally. #97 mostly solves this, but should probably also trigger fatal errors thrown from callbacks called in Queue::drain().

Unhandled promise

I think it's good that we have a method like set_exception_handler for promise that sets a user-defined unhandled promise rejection handler function

How am I supposed to deal with the last exception?

I have a code like this:

$promise->then(function() {
    // ...
    throw new FirstException();

})->then(null, function ($error) {
    // ...
    throw new SecondException();

});

SecondException() is lost, never handled.
But say for example that I have a PHP error handler that triggers exceptions.
Say then that I am in the middle of my work on the error handling closure (the second one above).
While I code it, I make mistakes, like usual.
How am I supposed to get the SecondException to my eyes so that I can have a great debugging experience? Adding a third "robust" ->then(null, 'debugProvedHandler')?
I'd prefer having an exception thrown from the last error handler be re-thrown, don't you?
Or any other way I'm missing?

Getting undefined function

Hi,

When using composer to install your lib I get the following error when consuming it.
Call to undefined function React\Promise\resolve()

Any idea what could be causing this?

Waiting for all promises to end

Hey, I have an array of promises.

I want to proceed only after all of the promises gave me a response no matter if they were resolved or reject. I thought that all() function can handle it, but it looks like it works only when all of the promises in the array are resolved and without considering rejections for some of the promises.

What function can I use??

example: the function getUser returns a promise object. When all of the promises gave me a response, i would like to catch the trigger, whether the promise is resolved or rejected.

 array_push($this->users['users'], $this->userFetcher->getUser($userName));

Thanks :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.