Async is a relatively new programming pattern that allows you to easily write **non-blocking** code **as if you were using standard** blocking functions, all **without** the need for complex message exchange systems and synchronization handling for threaded programs, that only add overhead and complexity to your programs, making everything slower and error-prone.
This means that you can handle multiple updates, download/upload multiple files all together in one process, as if you were writing normal synchronous code + making everything a lot faster.
This will enable async mode for **only one** specific call of a MadelineProto function (by adding a **new** array parameter after all the required parameters):
This **will not work**, because the result of a function that uses `yield` is not the `return`ed value, but a [generator](https://www.php.net/manual/en/language.generators.overview.php), which is what the async AMPHP API is based on.
If the generator is not __passed to the AMPHP event loop__, execution of the function will not be resumed: when MadelineProto asynchronously obtains the result of the getInfo, execution of the function is never resumed, and the line with sendMessage is never called.
To avoid this problem, only call asynchronous functions in the event/callback update handler, or in functions called by the event/callback update handler, or inside a function passed to loop.
You can also call asynchronous functions created by you, within other asynchronous functions.
// You can also have an asynchronous get_updates (deprecated) loop in here, if you want to; just don't forget to use yield for all MadelineProto functions.
You can use the async version of MadelineProto functions **without** yield if you don't want the request to block, and you don't need the result of the function.
This is allowed, but the order of the function calls will not be guaranteed: you can use [call queues](https://docs.madelineproto.xyz/docs/USING_METHODS.html#queues) if you want to make sure the order of the calls remains the same.
See [async forking](#async-forking-does-async-green-thread-forking).
### Multiple async
```php
yield $MadelineProto->messages->sendMessage([
'multiple' => true,
['peer' => '@danogentili', 'message' => 'hi'],
['peer' => '@apony', 'message' => 'hi']
]);
```
This is the preferred way of combining multiple method calls: this way, the MadelineProto async WriteLoop will combine all method calls in one container, making everything WAY faster.
The result of this will be an array of results, whose type is determined by the original return type of the method (see [API docs](https://docs.madelineproto.xyz/API_docs)).
The order of method calls can be guaranteed (server-side, not by MadelineProto) by using [call queues](USING_METHODS.html#queues).
Setting attributes asynchronously is also supported (it's kind of useless, but it's useful if you have some custom logic, like for example a method that returns a custom ArrayAccess class with a set method that does something magical).
Sometimes, you have to call non-async functions in your code: that is allowed in async MadelineProto, you just have to call your functions normally without `yield`.
However, you shouldn't do (or need to do) this, because this renders async completely useless.
MadelineProto and AMPHP both provide a lot of async functions: all of MadelineProto's functions are async, for example; and AMPHP provides [multiple packages](https://amphp.org/packages) to work asynchronously with HTTP requests, websockets, databases (MySQL, redis, postgres, DNS, sockets and [much more](https://github.com/amphp/)!
When using AMPHP libraries, you just have to use them with yield, no need to start the event loop, as long as you're running the functions inside MadelineProto's update handler/loop.
Also, you should read the AMPHP docs, especially the [event loop docs](https://amphp.org/amp/event-loop/api): AMPHP provides multiple helper methods for executing actions repeatedly every N seconds in a non-blocking manner, or to defer execution of certain actions (aka async cron).
MadelineProto also provides a few generic async helper methods: when possible, always use MadelineProto's wrapped versions of the [amphp combinators](https://amphp.org/amp/promises/combinators) and [amphp helpers](https://amphp.org/amp/promises/miscellaneous) instead of original amphp methods (`all`, `any`, `some`, `first`, ...).
When using amphp's [artax](https://amphp.org/artax) to make high-speed asynchronous HTTP requests (downloading files, etc.), use MadelineProto's modified Artax client, instead.
It automatically supports the socks/HTTP proxies specified in MadelineProto's settings (will use proxies only if the file can't be downloaded normally), and soon DoH for greater security.
To use MadelineProto's artax client, instead of creating artax's default client:
```php
$client = new Amp\Artax\DefaultClient;
```
Simply get MadelineProto's artax client:
```php
$client = $MadelineProto->getHTTPClient();
```
From here it's like in the [artax docs](https://amphp.org/artax).
Ignoring exceptions is usually not good practice, so it's best to wrap the method you're calling in a closure with a try-catch with some error handling code inside of it, calling it right after that and passing it to callFork:
```php
$MadelineProto->callFork((function () use ($MadelineProto) {
**Note**: this is not the recommended method to make multiple method calls on the same instance of MadelineProto; use this only for non-API methods like `start()`; for API methods, use [multiple async](#multiple-async).
These methods can be used to wait for a certain amount of time for a result, and then throw an `Amp\TimeoutException` or simply continue execution if no result was obtained.
```
// Waits for the result for 2 seconds and then throws an \Amp\TimeoutException
MadelineProto provides a very useful async loop APIs, for executing operations periodically or on demand.
It's a more flexible and powerful alternative to AMPHP's [repeat](https://amphp.org/amp/event-loop/api#repeat), allowing dynamically changeable repeat periods, resumes and signaling.
All loop APIs are defined by one or more [interfaces](https://github.com/danog/MadelineProto/tree/master/src/danog/MadelineProto/Loop): however, to use them, you would usually have to extend only one of the [abstract class implementations](https://github.com/danog/MadelineProto/tree/master/src/danog/MadelineProto/Loop/Impl).
The `__toString` method still has to be implemented in order to get the name of the loop, that will be used by the MadelineProto logging mechanism every time the loop starts/exits/fails to start.
By default, an instance of MadelineProto MUST be passed to the constructor of the function, or **if** a custom constructor is defined, the `$this->API` property MUST be set to an instance of MadelineProto.
The loop can be instantiated and `start()`ed, and this will automatically run the code in the loop in background.
If, however, only your loop is started (without an event handling loop), you have to pass the promise returned by `$loop->start()` to `$MadelineProto->loop`.
Do NOT do this if you've already started `$MadelineProto->loop()`.
A way more useful loop that exposes APIs to pause and resume the execution of the loop, both from outside of the loop, and in a cron-like manner from inside of the loop.
*@param int $time For how long to pause the loop, if null will pause forever (until resume is called from outside of the loop)
*
*@return Promise
*/
public function pause($time = null): Promise;
/**
* Resume the loop.
*
*@return void
*/
public function resume();
}
```
Usually one would extend the [ResumableSignalLoop implementation](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php).
An example implementation can be seen in the [ResumableSignalLoop section of this page](#resumablesignalloop).
#### SignalLoop
Yet another loop interface that exposes APIs to send signals to the loop, useful to force the termination of a loop from the outside, or to send data into it.
Usually one would extend the [ResumableSignalLoop implementation](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Impl/ResumableSignalLoop.php).
An example implementation can be seen in the [ResumableSignalLoop section of this page](#resumablesignalloop).
If you want, you can also extend only the [SignalLoop implementation](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Impl/SignalLoop.php), but usually a combination of the SignalLoop and ResumableLoop implementations is used, so read on to find out how to do that.
#### ResumableSignalLoop
This is what you would usually use to build a full async loop.
All loop interfaces and loop implementations are combined into one single abstract class you can extend.
```php
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
The difference now is that you can use the `pause` method to pause execution of the loop for a certain period of time (in seconds, supports decimals).
If `null` is passed, execution will be suspended forever (or until `resume` is called from outside of the loop).
If the promise returned by `pause` (or by any other async method) is passed to `waitSignal`, and the result is yielded, execution will be suspended for the specified amount of time|forever, or until a signal is received through the `signal` method.
The passed signal will then be returned as result of the `waitSignal` method, and can be used to stop the loop, or simply as a message exchange mechanism.
#### GenericLoop
If you want a simpler way to use the `ResumableSignalLoop`, you can use the [GenericLoop](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Generic/GenericLoop.php).
The constructor accepts three parameters:
```php
/**
* Constructor
*
*@param \danog\MadelineProto\API $API Instance of MadelineProto
*@param callback $callback Callback to run
*@param string $name Fetcher name
*/
public function __construct($API, $callback, $name) { // ...
```
Example:
```php
use danog\MadelineProto\Loop\Generic\GenericLoop;
$loop = new GenericLoop(
$MadelineProto,
function () {
yield $this->API->messages->sendMessage(['peer' => '...', 'message' => 'Hi every 2 seconds']);
return 2;
},
"My super loop"
);
$loop->start();
```
The callback will be bound to the GenericLoop instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can access the API property, use the pause/waitSignal methods & so on).