jvrnt
jvrnt

Reputation: 655

reactPHP promises executed synchoniously

I'm trying to implement js-like promises with reactPHP. But for some reason methods executed synchronously, the end_at printed only after the promise is resolved.

Code:

function iterate() {


    $deferred = new \React\Promise\Deferred();

    sleep(2);

    $deferred->resolve();

    return $deferred->promise();

}

Route::get('test/async', function() {


    echo "start execution at ".time()."<br>"; // this executed first

    iterate()->then(function($result) {
        echo "got result result at ". time() . "<br>"; // this is second
    }, function($error) {

    }, function ($finally) {

    });


    echo "end at " . time(); // this is executed only after then().


}); 

Upvotes: 4

Views: 3517

Answers (2)

Daniele Cruciani
Daniele Cruciani

Reputation: 623

The problem in your code is that you are using a blocking function: sleep()

Here are cited some blocking calls: https://github.com/reactphp/react/wiki/FAQ

But promise by itself is asynchronous: it gives the abilities to declare the function to be called in the chain before those are been called.

In fact by calling a function you must wait until the function is executed, but declaring that "then you must run this", you are not really running it, as soon as the first call returned.

So

function iterate() {
    global $loop;

    $deferred = new \React\Promise\Deferred();

    $loop->addTimer(2, function () use ($deferred) {
        $deferred->resolve();
    });

    return $deferred->promise();

}

Route::get('test/async', function() {


    echo "start execution at ".time()."<br>"; // this executed first

    iterate()->then(function($result) {
        echo "got result result at ". time() . "<br>"; // this when solved
    }, function($error) {

    }, function ($finally) {

    });


    echo "end at " . time(); // this is executed only after iterate() and then() returns.


});

I supposed you have a global $loop = React\EventLoop\Factory::create();, most of the time it make sense.

Here $loop->addTimer() call return immediately, so iterate() returns the promise, unsolved, so the method then() is called immediately, and the sequencial execution goes on with your echo end at ...

then() method attach a behaviour to the returned promise, does not execute the function passed as argument. But first the promise must be returned, the problem is that sleep is not an async sleep, but it really sleeps for 2 seconds!

Note that you do not have a sleep counterpart in javascript you have setTimeout(), that behaves just like this $loop->addTimer()

Upvotes: 0

emarref
emarref

Reputation: 1311

The promise itself is not asynchronous. A promise on its own simply offers you the ability to run some code then a different callback based on success or failure, then chain several of these concepts together.

Asynchronous code can be executed using a module specific to your task. If you're attempting to make an HTTP request, you can use ReactPHP's http-client module. If you want to execute a system command asynchronously, you might consider using the child-process module.

If you're looking to do something entirely different or bespoke, you should abstract the work into its own asynchronous behaviour, similar to the Predis async library. Perhaps using the promise module to provide success/failure callbacks.

Upvotes: 5

Related Questions