sue/event-loop

提供基于reactphp的event-loop

1.2.0 2023-09-25 10:33 UTC

This package is auto-updated.

Last update: 2024-04-25 14:26:02 UTC


README

提供基于ReactPHP提供全局唯一的EventLoop

What is ReactPHP?

ReactPHP是一款基于PHP的事件驱动的组件。核心是提供EventLoop,然后提供基于EventLoop上的各种组件,比方说I/O处理,定时器等。

Table of Contents

loop

获取全局唯一eventLoop对象

use Sue\EventLoop\loop;

$loop = loop();

//loop启动后程序就会阻塞在这
//如果loop上没有任何待处理的callback, loop则自动退出
$loop->run();

//loop停止运行
$loop->stop(); 

isLoopRunning

判断全局的eventloop是不是正在运行中

setInterval(1, function () {
    if (isLoopRunning()) {
        echo "Loop is running";
    }
});
loop()->run();

await

await($promise, $timeout)启动一个临时eventloop来处理promise, 当promise被settle后终止当前eventloop. 该方法适用于传统的阻塞php模型(比如php-fpm)中使用异步的特性. 方法返回promise resolved的值或者抛出异常 *** 该方法无法在一个已启动eventloop中使用 ***

try {
    $promise = someIoHeavyOperation();
    $result = await($promise); //程序会阻塞在这里一直等待$promise被resolved或者rejected
    handle($result);
} catch (Throwable $e) {
    //error handle
} 
//await方法第个参数接受一个float作为promise的timeout,以免promise长时间阻塞程序流程
$result = await($promise, 10);

setTimeout

setTimeout方法可以在eventloop上添加一个一次性的timer

use Sue\EventLoop\setTimeout;
use Sue\EventLoop\loop;
use Sue\EventLoop\cancelTimer;

 //延迟5秒执行
setTimeout(5, function () {
    echo "hello world from 5 seconds ago";
});
loop()->run();

//提前终止执行
$timer = setTimeout(5, function () {
    echo "hello world from 5 seconds ago";
});
cancelTimer($timer);
loop()->run();

setInterval

setInterval方法可以在eventloop上添加一个可以重复执行的timer

use React\EventLoop\TimerInterface;

use function Sue\EventLoop\setInterval;
use function Sue\EventLoop\cancelTimer;

//每60秒执行一次
setInterval(60, function () {
    echo "one minute has been passed\n";
});

// 中止运行
$timer = setInterval(1, function (string $name, int $age, TimerInterface $timer) {
    if ($some_condition) {
        cancelTimer($timer);
    }
}, 'foo', 18);
loop()->run();

cancelTimer

cancelTimer可以取消一个已经注册的timer对象

use React\EventLoop\TimerInterface;

use function Sue\EventLoop\setInterval;
use function Sue\EventLoop\cancelTimer;

$timer = setInterval(1, function (TimerInterface $timer) {
        echo "working...\n";
});
if ($some_condition) {
    cancelTimer($timer);
}

nextTick

nextTick可以在eventloop上注册一个在下一轮tick时执行的回调 对比setTimeout(0, $callback), nextTick($callback)有更高优先级

use RuntimeException;
use Sue\EventLoop\Exceptions\PromiseCancelledException;

use function Sue\EventLoop\nextTick;

$promise = nextTick(function () {
    return "hello world";
});
$promise->then(function (string $content) {
    //handler
});

//异常处理
$promise = nextTick(function () {
    throw new RuntimeException('boom');
});
$promise->then(null, function (RuntimeException $e) {
    echo "error: " . $e;
});

//中止执行
$promise = nextTick(function () {
    return "hello world";
});
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

throttle

throttle(节流)可以在eventloop上创建一个一次性的timer,但是会在N秒内同样的操作只会执行一次

use Sue\EventLoop\loop;
use Sue\EventLoop\throttle;
use Sue\EventLoop\setInterval;

$callback = function () {
    echo "hello world\n";
};
setInterval(1, function () use ($callback) {
    static $count = 10;
    while ($count--) {
        echo "tick\n";
        throttle(3, $callback);
    }
});
loop()->run();

/** expect output
tick
tick
tick
hello world
tick
tick
tick
hello world
tick
tick
tick
hello world
tick
**/

//如果想提前手动中止
$promise = throttle(3, $callback);
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

throttleById

throttleById方法同throttle,除了需要自行设置唯一id值,throttle是由callable的性质来计算唯一id

debounce

debounce(防抖)可以在eventloop上注册一个一次性timer, 但是在N秒内每次同样的操作都会延迟N秒后再执行

use Sue\EventLoop\loop;
use Sue\EventLoop\debounce;
use Sue\EventLoop\setInterval;

$callback = function () {
    echo "hello world\n";
};
debounce(1, function () use ($callback) {
    static $count = 10;
    while ($count--) {
        echo "tick\n";
        throttle(3, $callback);
    }
});
loop()->run();
/** expect output
tick
tick
tick
tick
tick
tick
tick
tick
tick
tick
hello world
**/

//如果想提前中止
$promise = debounce(1, $callback);
if ($some_condition) {
    $promise->cancel();
}
$promise->otherwise(function (PromiseCancelledException $exception) {
    //exception
});

debounceById

debounceById方法同debounce,除了需要自行设置唯一id值

install

$ composer require sue/event-loop

tests

git clone项目后执行

$ composer install
$ ./vendor/bin/phpunit

License

The MIT License (MIT)

Copyright (c) 2023 Donghai Zhang

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.