m3m0r7/async-promise

一个用PHP编写的异步Promise库

0.0.1 2023-03-02 06:49 UTC

This package is auto-updated.

Last update: 2024-09-30 01:52:20 UTC


README

英文 | 日语

AsyncPromise

什么是AsyncPromise?

AsyncPromise是一个PHP库,用于实现与JavaScript Promise相似的并发处理。

要求

  • PHP 8.1或更高版本
  • Swoole(如果您使用SwooleDriver)

如何安装

您可以使用以下命令进行安装

$ composer require m3m0r7/async-promise

如何使用

入门

Promise可以使用与JavaScript相同的方式进行使用,如下所示

<?php

use AsyncPromise\Promise;

(new Promise(function (callable $resolve) {
    $resolve('resolved!');
}))->then(function ($result) {
    // Show `resolved!`
    echo $result;
});

您可以使用catch方法接收异常。

<?php

use AsyncPromise\Promise;

(new Promise(function (callable $resolve) {
    throw new Exception('An error occurred');
}))->catch(function ($reason) {
    // Show `An error occurred`
    echo $reason;
});

或者,您可以通过Promise回调函数的第二个参数来处理拒绝。

<?php

use AsyncPromise\Promise;

(new Promise(function (callable $_, callable $reject) {
    $reject('An error occurred');
}))->catch(function ($reason) {
    // Show `An error occurred`
    echo $reason;
});

then方法可以进行多重链式调用。

<?php

use AsyncPromise\Promise;

(new Promise(function (callable $resolve) {
    $resolve('resolved!');
}))->then(function ($result) {
    return 'nested chain: ' . $result;
})->then(function ($result) {
    // Show `nested chain: resolved!`
    echo $result;
});

在调用thencatch方法后,如果您想运行某些操作,可以使用finally

<?php

use AsyncPromise\Promise;

(new Promise(function (callable $resolve) {
    $resolve('resolved!');
}))->then(function ($result) {
    return 'nested chain: ' . $result;
}, function ($reason) {
    echo $reason;
})->finally(function ($result) {
    echo "Finally was reached";
});

Promise::all(array)

当所有传入的Promises都得到满足时,返回一个新的Promise。

<?php

use AsyncPromise\Promise;

Promise::all([
    65535,
    'text',
    (new Promise(fn (callable $resolve) => $resolve('fulfilled1'))),
    ['key' => 'value'],
    (new Promise(fn (callable $resolve) => $resolve('fulfilled2'))),
])->then(function (array $values) {
    // Show as following:
    //
    // Array
    // (
    //    [0] => 65535
    //    [1] => text
    //    [2] => fulfilled1
    //    [3] => Array
    //        (
    //            [key] => value
    //        )
    //
    //    [4] => fulfilled2
    // )
    print_r($values);
});

它将一直运行,直到拒绝,如下所示

<?php

use AsyncPromise\Promise;

Promise::all([
    65535,
    'text',
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected'))),
])->then(function (array $values) {
    // This statement is unreachable.
    print_r($values);
})->catch(function (string $reason) {
    // Show `rejected`
    echo $reason;
});

Promise::allSettled(array)

当所有传入的Promises都被处理时,返回一个新的Promise。

<?php

use AsyncPromise\Promise;

Promise::allSettled([
    65535,
    'text',
    (new Promise(fn (callable $resolve) => $resolve('resolved'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected'))),
])->then(function (array $values) {
    foreach ($values as $value) {
        if ($value->status === Promise::FULFILLED) {
            // Show as following:
            //   fulfilled: 65535
            //   fulfilled: text
            //   fulfilled: resolved
            echo "{$value->status}: {$value->value}\n";
        }
        if ($value->status === Promise::REJECTED) {
            // Show as following:
            //   rejected: rejected
            echo "{$value->status}: {$value->reason}\n";
        }
    }
});

Promise::race(array)

当传入的Promises之一被处理时,返回一个新的Promise。

<?php

use AsyncPromise\Promise;

Promise::race([
    (new Promise(fn (callable $resolve) => $resolve('resolved1'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))),
    (new Promise(fn (callable $resolve) => $resolve('resolved2'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))),
])->then(function ($value) {
    // Show `resolved1`
    echo "{$value}\n";
});

Promise::any(array)

当传入的Promises之一被满足时,返回一个新的Promise。

<?php

use AsyncPromise\Promise;

Promise::any([
    (new Promise(fn (callable $resolve) => $resolve('resolved1'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))),
    (new Promise(fn (callable $resolve) => $resolve('resolved2'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))),
])->then(function ($value) {
    // Show `resolved1`
    echo "{$value}\n";
});

如果没有满足,它将链接到catch方法。

<?php

use AsyncPromise\Promise;

Promise::any([
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected3'))),
    (new Promise(fn (callable $_, callable $reject) => $reject('rejected4'))),
])->catch(function (array $values) {
    // Show as following:
    //
    // Array
    // (
    //     [0] => rejected1
    //     [1] => rejected2
    //     [2] => rejected3
    //     [3] => rejected4
    // )
    print_r($values);
});

Promise::resolve(mixed)

将解决Promise。

<?php

use AsyncPromise\Promise;

Promise::resolve('resolved1')
    ->then(function (string $value) {
        // Show `resolved1`
        echo "resolved1\n";
    });

将拒绝Promise。

<?php

use AsyncPromise\Promise;

Promise::reject('resolved1')
    ->catch(function (string $value) {
        // Show `resolved1`
        echo "resolved1\n";
    });

Promise::reject(string)

驱动程序

您可以选择运行并发驱动程序。AsyncPromise实现了以下内容

  • \AsyncPromise\Driver\SwooleDriver
  • \AsyncPromise\Driver\FiberDriver
  • \AsyncPromise\Driver\PcntlDriver (实验性)
  • \AsyncPromise\Driver\PolyfillDriver

切换其他驱动程序

Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class);

(new Promise(...))->then(...);

如果您使用SwooleDriver,必须在Promise::createContext(...)上下文中运行Promise。

Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class);

Promise::createContext(function () {
    (new Promise(fn (callable $resolve) => $resolve('resolved with SwooleDriver')))
        // Show `resolved with SwooleDriver`
        ->then(fn ($result) => print($result));
});

使用SwooleDriver时,您将获得并发的好处。以下命令是获取SwooleDriver性能的命令

Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class);

// sleep function to be coroutinized.
\Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_SLEEP);

Promise::createContext(function () {
    $start = time();
    Promise::all([
        new Promise(function (callable $resolve) {
            sleep(3);
            $resolve();
        }),
        new Promise(function (callable $resolve) {
            sleep(5);
            $resolve();
        }),
    ])->then(function ($values) use ($start) {
        // Show `Take 5 sec`
        echo "Take " . (time() - $start) . " sec";
    });
});

PolyfillDriver是当没有安装并发驱动程序时的虚拟进程驱动程序。因此,PolyfillDriver不会提高性能,因为它是在同步中运行的。例如,运行上述代码将显示“用时8秒”。

如何测试

您可以使用以下命令运行测试

./vendor/bin/phpunit tests/