Git Product home page Git Product logo

async's Introduction

Async Utilities

CI status installs on Packagist

Async utilities and fibers for ReactPHP.

This library allows you to manage async control flow. It provides a number of combinators for Promise-based APIs. Instead of nesting or chaining promise callbacks, you can declare them as a list, which is resolved sequentially in an async manner. React/Async will not automagically change blocking code to be async. You need to have an actual event loop and non-blocking libraries interacting with that event loop for it to work. As long as you have a Promise-based API that runs in an event loop, it can be used with this library.

Table of Contents

Usage

This lightweight library consists only of a few simple functions. All functions reside under the React\Async namespace.

The below examples refer to all functions with their fully-qualified names like this:

React\Async\await(…);

As of PHP 5.6+ you can also import each required function into your code like this:

use function React\Async\await;

await(…);

Alternatively, you can also use an import statement similar to this:

use React\Async;

Async\await(…);

async()

The async(callable():(PromiseInterface<T>|T) $function): (callable():PromiseInterface<T>) function can be used to return an async function for a function that uses await() internally.

This function is specifically designed to complement the await() function. The await() function can be considered blocking from the perspective of the calling code. You can avoid this blocking behavior by wrapping it in an async() function call. Everything inside this function will still be blocked, but everything outside this function can be executed asynchronously without blocking:

Loop::addTimer(0.5, React\Async\async(function () {
    echo 'a';
    React\Async\await(React\Promise\Timer\sleep(1.0));
    echo 'c';
}));

Loop::addTimer(1.0, function () {
    echo 'b';
});

// prints "a" at t=0.5s
// prints "b" at t=1.0s
// prints "c" at t=1.5s

See also the await() function for more details.

Note that this function only works in tandem with the await() function. In particular, this function does not "magically" make any blocking function non-blocking:

Loop::addTimer(0.5, React\Async\async(function () {
    echo 'a';
    sleep(1); // broken: using PHP's blocking sleep() for demonstration purposes
    echo 'c';
}));

Loop::addTimer(1.0, function () {
    echo 'b';
});

// prints "a" at t=0.5s
// prints "c" at t=1.5s: Correct timing, but wrong order
// prints "b" at t=1.5s: Triggered too late because it was blocked

As an alternative, you should always make sure to use this function in tandem with the await() function and an async API returning a promise as shown in the previous example.

The async() function is specifically designed for cases where it is used as a callback (such as an event loop timer, event listener, or promise callback). For this reason, it returns a new function wrapping the given $function instead of directly invoking it and returning its value.

use function React\Async\async;

Loop::addTimer(1.0, async(function () { … }));
$connection->on('close', async(function () { … }));
$stream->on('data', async(function ($data) { … }));
$promise->then(async(function (int $result) { … }));

You can invoke this wrapping function to invoke the given $function with any arguments given as-is. The function will always return a Promise which will be fulfilled with whatever your $function returns. Likewise, it will return a promise that will be rejected if you throw an Exception or Throwable from your $function. This allows you to easily create Promise-based functions:

$promise = React\Async\async(function (): int {
    $browser = new React\Http\Browser();
    $urls = [
        'https://example.com/alice',
        'https://example.com/bob'
    ];

    $bytes = 0;
    foreach ($urls as $url) {
        $response = React\Async\await($browser->get($url));
        assert($response instanceof Psr\Http\Message\ResponseInterface);
        $bytes += $response->getBody()->getSize();
    }
    return $bytes;
})();

$promise->then(function (int $bytes) {
    echo 'Total size: ' . $bytes . PHP_EOL;
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

The previous example uses await() inside a loop to highlight how this vastly simplifies consuming asynchronous operations. At the same time, this naive example does not leverage concurrent execution, as it will essentially "await" between each operation. In order to take advantage of concurrent execution within the given $function, you can "await" multiple promises by using a single await() together with Promise-based primitives like this:

$promise = React\Async\async(function (): int {
    $browser = new React\Http\Browser();
    $urls = [
        'https://example.com/alice',
        'https://example.com/bob'
    ];

    $promises = [];
    foreach ($urls as $url) {
        $promises[] = $browser->get($url);
    }

    try {
        $responses = React\Async\await(React\Promise\all($promises));
    } catch (Exception $e) {
        foreach ($promises as $promise) {
            $promise->cancel();
        }
        throw $e;
    }

    $bytes = 0;
    foreach ($responses as $response) {
        assert($response instanceof Psr\Http\Message\ResponseInterface);
        $bytes += $response->getBody()->getSize();
    }
    return $bytes;
})();

$promise->then(function (int $bytes) {
    echo 'Total size: ' . $bytes . PHP_EOL;
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

The returned promise is implemented in such a way that it can be cancelled when it is still pending. Cancelling a pending promise will cancel any awaited promises inside that fiber or any nested fibers. As such, the following example will only output ab and cancel the pending delay(). The await() calls in this example would throw a RuntimeException from the cancelled delay() call that bubbles up through the fibers.

$promise = async(static function (): int {
    echo 'a';
    await(async(static function (): void {
        echo 'b';
        delay(2);
        echo 'c';
    })());
    echo 'd';

    return time();
})();

$promise->cancel();
await($promise);

await()

The await(PromiseInterface<T> $promise): T function can be used to block waiting for the given $promise to be fulfilled.

$result = React\Async\await($promise);

This function will only return after the given $promise has settled, i.e. either fulfilled or rejected. While the promise is pending, this function can be considered blocking from the perspective of the calling code. You can avoid this blocking behavior by wrapping it in an async() function call. Everything inside this function will still be blocked, but everything outside this function can be executed asynchronously without blocking:

Loop::addTimer(0.5, React\Async\async(function () {
    echo 'a';
    React\Async\await(React\Promise\Timer\sleep(1.0));
    echo 'c';
}));

Loop::addTimer(1.0, function () {
    echo 'b';
});

// prints "a" at t=0.5s
// prints "b" at t=1.0s
// prints "c" at t=1.5s

See also the async() function for more details.

Once the promise is fulfilled, this function will return whatever the promise resolved to.

Once the promise is rejected, this will throw whatever the promise rejected with. If the promise did not reject with an Exception or Throwable, then this function will throw an UnexpectedValueException instead.

try {
    $result = React\Async\await($promise);
    // promise successfully fulfilled with $result
    echo 'Result: ' . $result;
} catch (Throwable $e) {
    // promise rejected with $e
    echo 'Error: ' . $e->getMessage();
}

coroutine()

The coroutine(callable(mixed ...$args):(\Generator|PromiseInterface<T>|T) $function, mixed ...$args): PromiseInterface<T> function can be used to execute a Generator-based coroutine to "await" promises.

React\Async\coroutine(function () {
    $browser = new React\Http\Browser();

    try {
        $response = yield $browser->get('https://example.com/');
        assert($response instanceof Psr\Http\Message\ResponseInterface);
        echo $response->getBody();
    } catch (Exception $e) {
        echo 'Error: ' . $e->getMessage() . PHP_EOL;
    }
});

Using Generator-based coroutines is an alternative to directly using the underlying promise APIs. For many use cases, this makes using promise-based APIs much simpler, as it resembles a synchronous code flow more closely. The above example performs the equivalent of directly using the promise APIs:

$browser = new React\Http\Browser();

$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
    echo $response->getBody();
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

The yield keyword can be used to "await" a promise resolution. Internally, it will turn the entire given $function into a Generator. This allows the execution to be interrupted and resumed at the same place when the promise is fulfilled. The yield statement returns whatever the promise is fulfilled with. If the promise is rejected, it will throw an Exception or Throwable.

The coroutine() function will always return a Promise which will be fulfilled with whatever your $function returns. Likewise, it will return a promise that will be rejected if you throw an Exception or Throwable from your $function. This allows you to easily create Promise-based functions:

$promise = React\Async\coroutine(function () {
    $browser = new React\Http\Browser();
    $urls = [
        'https://example.com/alice',
        'https://example.com/bob'
    ];

    $bytes = 0;
    foreach ($urls as $url) {
        $response = yield $browser->get($url);
        assert($response instanceof Psr\Http\Message\ResponseInterface);
        $bytes += $response->getBody()->getSize();
    }
    return $bytes;
});

$promise->then(function (int $bytes) {
    echo 'Total size: ' . $bytes . PHP_EOL;
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

The previous example uses a yield statement inside a loop to highlight how this vastly simplifies consuming asynchronous operations. At the same time, this naive example does not leverage concurrent execution, as it will essentially "await" between each operation. In order to take advantage of concurrent execution within the given $function, you can "await" multiple promises by using a single yield together with Promise-based primitives like this:

$promise = React\Async\coroutine(function () {
    $browser = new React\Http\Browser();
    $urls = [
        'https://example.com/alice',
        'https://example.com/bob'
    ];

    $promises = [];
    foreach ($urls as $url) {
        $promises[] = $browser->get($url);
    }

    try {
        $responses = yield React\Promise\all($promises);
    } catch (Exception $e) {
        foreach ($promises as $promise) {
            $promise->cancel();
        }
        throw $e;
    }

    $bytes = 0;
    foreach ($responses as $response) {
        assert($response instanceof Psr\Http\Message\ResponseInterface);
        $bytes += $response->getBody()->getSize();
    }
    return $bytes;
});

$promise->then(function (int $bytes) {
    echo 'Total size: ' . $bytes . PHP_EOL;
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

delay()

The delay(float $seconds): void function can be used to delay program execution for duration given in $seconds.

React\Async\delay($seconds);

This function will only return after the given number of $seconds have elapsed. If there are no other events attached to this loop, it will behave similar to PHP's sleep() function.

echo 'a';
React\Async\delay(1.0);
echo 'b';

// prints "a" at t=0.0s
// prints "b" at t=1.0s

Unlike PHP's sleep() function, this function may not necessarily halt execution of the entire process thread. Instead, it allows the event loop to run any other events attached to the same loop until the delay returns:

echo 'a';
Loop::addTimer(1.0, function (): void {
    echo 'b';
});
React\Async\delay(3.0);
echo 'c';

// prints "a" at t=0.0s
// prints "b" at t=1.0s
// prints "c" at t=3.0s

This behavior is especially useful if you want to delay the program execution of a particular routine, such as when building a simple polling or retry mechanism:

try {
    something();
} catch (Throwable) {
    // in case of error, retry after a short delay
    React\Async\delay(1.0);
    something();
}

Because this function only returns after some time has passed, it can be considered blocking from the perspective of the calling code. You can avoid this blocking behavior by wrapping it in an async() function call. Everything inside this function will still be blocked, but everything outside this function can be executed asynchronously without blocking:

Loop::addTimer(0.5, React\Async\async(function (): void {
    echo 'a';
    React\Async\delay(1.0);
    echo 'c';
}));

Loop::addTimer(1.0, function (): void {
    echo 'b';
});

// prints "a" at t=0.5s
// prints "b" at t=1.0s
// prints "c" at t=1.5s

See also the async() function for more details.

Internally, the $seconds argument will be used as a timer for the loop so that it keeps running until this timer triggers. This implies that if you pass a really small (or negative) value, it will still start a timer and will thus trigger at the earliest possible time in the future.

The function is implemented in such a way that it can be cancelled when it is running inside an async() function. Cancelling the resulting promise will clean up any pending timers and throw a RuntimeException from the pending delay which in turn would reject the resulting promise.

$promise = async(function (): void {
    echo 'a';
    delay(3.0);
    echo 'b';
})();

Loop::addTimer(2.0, function () use ($promise): void {
    $promise->cancel();
});

// prints "a" at t=0.0s
// rejects $promise at t=2.0
// never prints "b"

parallel()

The parallel(iterable<callable():PromiseInterface<T>> $tasks): PromiseInterface<array<T>> function can be used like this:

<?php

use React\EventLoop\Loop;
use React\Promise\Promise;

React\Async\parallel([
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for a whole second');
            });
        });
    },
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for another whole second');
            });
        });
    },
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for yet another whole second');
            });
        });
    },
])->then(function (array $results) {
    foreach ($results as $result) {
        var_dump($result);
    }
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

series()

The series(iterable<callable():PromiseInterface<T>> $tasks): PromiseInterface<array<T>> function can be used like this:

<?php

use React\EventLoop\Loop;
use React\Promise\Promise;

React\Async\series([
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for a whole second');
            });
        });
    },
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for another whole second');
            });
        });
    },
    function () {
        return new Promise(function ($resolve) {
            Loop::addTimer(1, function () use ($resolve) {
                $resolve('Slept for yet another whole second');
            });
        });
    },
])->then(function (array $results) {
    foreach ($results as $result) {
        var_dump($result);
    }
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

waterfall()

The waterfall(iterable<callable(mixed=):PromiseInterface<T>> $tasks): PromiseInterface<T> function can be used like this:

<?php

use React\EventLoop\Loop;
use React\Promise\Promise;

$addOne = function ($prev = 0) {
    return new Promise(function ($resolve) use ($prev) {
        Loop::addTimer(1, function () use ($prev, $resolve) {
            $resolve($prev + 1);
        });
    });
};

React\Async\waterfall([
    $addOne,
    $addOne,
    $addOne
])->then(function ($prev) {
    echo "Final result is $prev\n";
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

Todo

  • Implement queue()

Install

The recommended way to install this library is through Composer. New to Composer?

This project follows SemVer. This will install the latest supported version from this branch:

composer require react/async:^4.3

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP extensions and supports running on PHP 8.1+. It's highly recommended to use the latest supported PHP version for this project.

We're committed to providing long-term support (LTS) options and to provide a smooth upgrade path. If you're using an older PHP version, you may use the 3.x branch (PHP 7.1+) or 2.x branch (PHP 5.3+) which both provide a compatible API but do not take advantage of newer language features. You may target multiple versions at the same time to support a wider range of PHP versions like this:

composer require "react/async:^4 || ^3 || ^2"

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

On top of this, we use PHPStan on max level to ensure type safety across the project:

vendor/bin/phpstan

License

MIT, see LICENSE file.

This project is heavily influenced by async.js.

async's People

Contributors

cboden avatar clue avatar igorw avatar nhedger avatar simonfrings 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

async's Issues

Using await in a destructor

👋 I've ran into an issue with using await in a destructor. The error triggered is Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in SimpleFiber.php on line 66.

index.php

<?php

declare(strict_types=1);

use function React\Async\await;

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

$foo = new class {

    public function __construct()
    {
        await(\React\Promise\Timer\sleep(1));
        print "construct\n";
    }

    public function __destruct()
    {
        await(\React\Promise\Timer\sleep(1));
        print "destruct\n";
    }

};

Using the 4.x branch; the issue seems to exit with both StreamSelectLoop and ExtUvLoop.

Struggling with the simplest example

Hi everybody,

<?php
require __DIR__ . '/async/vendor/autoload.php';

use React\EventLoop\Loop;
use React\Promise\Promise;
use function React\Async\await;
use function React\Async\async;


Loop::addTimer(0.5, React\Async\async(function() {
    echo 'a';
    React\async\await(React\Promise\Timer\sleep(1.0));
    echo 'c'; // not echoed?
}));

Loop::addTimer(1.0, fn() => echo 'b'); // line 16

I am already struggling with the simplest example (copied from the main page).
I am using PHP 8.1.2 on Win10 with the newest async.

  1. There is an unexpected token "echo" in line 16.
  2. When I comment line 16 with // in the beginning, the output is just 'a' (without 'c') - why not 'ac'?

Thank you!

Error: event_base_loop reentrant invocation

Hello.
The following code is causing an error:
EventBase::loop(): event_base_loop: reentrant invocation. Only one event_base_loop can run on each event_base at once.

<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;
use function React\Async\await;

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

Loop::addTimer(0, function () {
	$deferred = new Deferred();
	Loop::addTimer(0, static fn() => $deferred->resolve());
	await($deferred->promise());
});

Tested on ExtEventLoop.

Use 0.x versions

Hello there,

Now that react/async is open to public, would you consider using 0.x.x versions until 1.0 is not finalized instead of relying on commit hashes?

It took me a while after realizing an important BC break introduced by 4355fcf after a composer update 🤠

With a semver-like approach, BC breaks would be easier to spot. WDYT?

Basic question 'bout reactphp

Hi,

Sorry, for this - again - basic question about reactphp

To make my question more clear, I use this DNS lookup example:

<?php
$result = [];
$domains = ['domain1.com', 'domain2.xyz'];

foreach ($domains as $domain) {
    $result[] = dns_get_record($domain);
}

var_dump($result);

Can above example executed in parallel (to make it faster) with reactphp or not (and if yes, how with async? or event-loop? can you give me an additional hint)?
If I understand this stackoverflow post correctly, it can not (but I do not think so).

Thank you again.

await() error in SimpleFiber.php

(Great job with Fibers initiative!)
For test purposes I'm refactoring my app with await() function in place of promises-chains. I've got an error:

2021-11-29 21:56:23 [EXCEPTION] Error: Value of type null is not callable in ...\vendor\react\async\src\SimpleFiber.php:59
2021-11-29 21:56:23 [EXCEPTION] #0 ...\vendor\react\async\src\functions.php(92): React\Async\SimpleFiber->suspend()
2021-11-29 21:56:23 [EXCEPTION] #1 ...\MessagesProcessor.php(114): React\Async\await(Object(React\Promise\Promise))

It occurs when I try to use async() function. It's hard to say how to reproduce this bug. In the same call stack, a few promises before, I use a React\Http\Browser with async() function. If I comment this usage (replace to something like resolve(new ResultObject())) - error doesn't occur. If I use Browser with promise-style api, the PHP process ends with error:

Process finished with exit code -1073741819 (0xC0000005)

I'm using the newest versions of all packages, ofc PHP 8.1.
Do you know what can cause these errors?

Support Promise v3

We should support Promise v3 for Async v2, v3 and v4. I don't think implementing this here requires a lot of work, the only outstanding feature that would be debatable is cancellation semantics as discussed in #42.

I'm not currently working on this, but figured it makes sense to report here in order to track this feature request. In case anybody feels like picking this up, any input and PRs would be much appreciated 👍

Allow `iterable` instead of `array` for `parallel()`, `series()` and `waterfall()`

We should support accepting an iterable instead of only an array for parallel(), series() and waterfall(). The iterable pseudo type is available as of PHP 7.1, so we can take advantage of this for our Async v3 and Async v4 (see also #11 and #14). It supports passing an array just like now, but also accepts Iterators and Generators.

I'm not currently working on this, but figured it makes sense to report here in order to track this feature request. In case anybody feels like picking this up, any input and PRs would be much appreciated 👍 (I've also filed the same suggestion for Promise v3 in reactphp/promise#221)

Cancellation semantics for `async()` and `coroutine()`

What should the following code return?

$promise = async(static function (): int {
    try {
        await(React\Promise\Timer\sleep(2));
    } catch (Exception $e) {
        return 1;
    }

    return 2;
})();

$promise->cancel();

var_dump(await($promise));

At the moment, the code would print 1. The same cancellation logic is triggered for fibers (#20) and coroutines (#13). Accordingly, this affects Async v3 and Async v4.

Perhaps we should reject the entire promise? (See also reactphp/promise#56 for discussion about cancellation semantics in Promise v3).

Improve error reporting when incorrectly using `await()` (Value of type null is not callable in src/SimpleFiber.php:66)

Reproduce:

use React\EventLoop\Factory as Loop;
use React\Async;
use React\Promise\Deferred;

$loop = Loop::create();

$deferred = new Deferred;
$promise = $deferred->promise();
$loop->addTimer(0.02, function() use($deferred) {
    $deferred->resolve();
});

$foo = function() use($promise) {
    Async\await($promise);
    echo 'All good' . PHP_EOL;    
};

$loop->addTimer(0.01, $foo);

$loop->run();

How to fix it is known: wrap $foo into Async\async. But the error sucks anyway. You guys gotta find a way to get it either work anyway, or throw a nice error telling us what is wrong and hinting what to do.

await() doesn't work with streaming HTTP response body

Hello,

The code below doesn't work as expected.
At the end, strlen() should return a non-zero.

Am I missing something maybe?

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

React\Async\async(function (): void {
	$browser = new React\Http\Browser();
	$response = $browser->requestStreaming(
		'GET',
		'https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1920_18MG.mp4',
		[
			'Range' => 'bytes=0-499',
		],
	);

	/** @var Psr\Http\Message\ResponseInterface */
	$response = React\Async\await($response);

	/** @var React\Stream\ReadableStreamInterface */
	$body = $response->getBody();

	$body = React\Promise\Stream\buffer($body);
	$body = React\Async\await($body);

	echo strlen($body), "\n"; // 0
})();

\React\Async\async did not invokes in on('data') event

I have TCP client

$connector = new \React\Socket\Connector(); that connect to server and listen.

I add handler to 'data' event.

// did not write to event.log
$connector = new \React\Socket\Connector();
$connector->connect($host)->then(function (\React\Socket\ConnectionInterface $connection) {
    $connection->on('data', \React\Async\async(
        function ($data) {
            file_put_contents('/home/carsak/event.log', $data . PHP_EOL, FILE_APPEND);
        }
    ));
});

function inside async did not invoked

but if I wrote without async function, function write logs into event.log file

// it works
$connector = new \React\Socket\Connector();
$connector->connect($host)->then(function (\React\Socket\ConnectionInterface $connection) {
    $connection->on('data',
        function ($data) {
            file_put_contents('/home/bitrix/dialer/event.log', $data . PHP_EOL, FILE_APPEND);
        }
    );
});

I checked docs several times and read about

The async() function is specifically designed for cases where it is used as a callback (such as an event loop timer, event listener, or promise callback). For this reason, it returns a new function wrapping the given $function instead of directly invoking it and returning its value.

Follow the example

use function React\Async\async;

Loop::addTimer(1.0, async(function () { … }));
$connection->on('close', async(function () { … }));
$stream->on('data', async(function ($data) { … }));
$promise->then(async(function (int $result) { … }));

My composer.json

{
  "require": {
    "react/socket": "1.12",
    "react/event-loop": "1.3",
    "ext-pdo": "*",
    "ext-curl": "*",
    "monolog/monolog": "^2.9",
    "elasticsearch/elasticsearch": "^8.8",
    "react/async": "^4.2"
  },
  "config": {
    "allow-plugins": {
      "php-http/discovery": true
    }
  }
}

What I did wrong?

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.