skelan/simple-promise

这是一个轻量级的Promise包实现

v0.2.4 2022-07-26 08:00 UTC

This package is auto-updated.

Last update: 2024-09-26 12:49:17 UTC


README

PHP的轻量级CommonJS Promises/A实现。

此文件的大部分代码来自react/promise,感谢reactphp团队提供了这样一个有用的包。

安装

确保您已安装Composer Composer

如果没有Composer,请运行以下命令

curl -sS https://getcomposer.org/installer | php

运行安装

composer require skelan/simple-promise

概念

Deferred

Deferred 代表一个可能尚未完成的计算或工作单元。通常(但并非总是),这种计算将是在未来某个时刻异步执行并完成的。

Promise

虽然Deferred代表计算本身,但Promise代表该计算的结果。因此,每个Deferred都有一个Promise,它充当其实际结果的占位符。

API

Deferred

Deferred代表一个解决状态待定的操作。它有独立的promise和resolver部分。

$deferred = new Skelan\SimplePromise\Deferred();

$promise = $deferred->promise();

$deferred->resolve(mixed $value = null);
$deferred->reject(mixed $reason = null);

Promise转发的工作原理

一些简单的例子,展示Promises/A转发的工作机制。当然,这些例子是人为构造的,在实际使用中,promise链通常跨越多个函数调用,甚至跨越您的应用架构的几个级别。

解决转发

已解决的Promise将解决值转发到下一个Promise。第一个Promise,$deferred->promise(),将使用下面传递给$deferred->resolve()的值进行解决。

每次调用then()都会返回一个新的Promise,它将解决上一个处理器的返回值。这创建了一个Promise“管道”。

$deferred = new Skelan\SimplePromise\Deferred();

$deferred->promise()
    ->then(function ($x) {
        // $x will be the value passed to $deferred->resolve() below
        // and returns a *new promise* for $x + 1
        return $x + 1;
    })
    ->then(function ($x) {
        // $x === 2
        // This handler receives the return value of the
        // previous handler.
        return $x + 1;
    })
    ->then(function ($x) {
        // $x === 3
        // This handler receives the return value of the
        // previous handler.
        return $x + 1;
    })
    ->then(function ($x) {
        // $x === 4
        // This handler receives the return value of the
        // previous handler.
        echo 'Resolve ' . $x;
    });

$deferred->resolve(1); // Prints "Resolve 4"

拒绝转发

拒绝的Promise行为类似,并且与try/catch类似:当你捕获异常时,你必须重新抛出才能使其传播。

同样,当你处理拒绝的Promise时,为了传播拒绝,可以通过返回一个拒绝的Promise或实际抛出(因为Promise将抛出的异常转换为拒绝)来“重新抛出”。

$deferred = new Skelan\SimplePromise\Deferred();

$deferred->promise()
    ->then(function ($x) {
        throw new \Exception($x + 1);
    })
    ->otherwise(function (\Exception $x) {
        // Propagate the rejection
        throw $x;
    })
    ->otherwise(function ($x) {
        echo 'Reject ' . $x->getMessage(); // 3
    });

$deferred->resolve(1);  // Prints "Reject 3"

最佳实践

1) try/catch演示

就像try/catch一样,你可以选择是否传播。混合解决方案和拒绝仍将以可预测的方式转发处理器结果。

try {
  return doSomething();
} catch(\Exception $e) {
    return handleError($e);
} finally {
    doFinally();  
}
$deferred = new Skelan\SimplePromise\Deferred();

$deferred->promise()
    ->then(function ($x) {
        return $x + 1;
    })
    ->then(function ($x) {
        throw new \Exception($x + 1);
    })
    ->otherwise(function (\Exception $x) { 
        //catch exception 
        var_dump('otherwise: ' . ($x->getMessage() + 1)); //4
    })
    ->always(function () { 
        //finally
        var_dump('finally ');
    });

$deferred->resolve(1); 

2) 异步调用

swoole是PHP的一个很棒的扩展

function remoteRequest() {
    $deferred = new \Skelan\SimplePromise\Deferred(function (\Skelan\SimplePromise\PromiseInterface $promise) {
        var_dump('call cancel.');
    });

    \Swoole\Timer::after(1000, function() use($deferred) {
        $deferred->resolve('finish: ' . time());
    });

    return $deferred->promise();
}

remoteRequest()->then(function ($value) {
    var_dump('resolve: ' . time());
    var_dump($value);
    throw new \Exception('xxx');
}, function($reason) {
    var_dump($reason);
})->otherwise(function(\Throwable $exception) {
    var_dump('exception: ' . $exception->getMessage());
})->always(function($value) {
    var_dump('otherwise: ' . $value);
});

许可

MIT许可下发布。