PHP 的 CommonJS Promises/A 的轻量级实现。
Promise 是一个为 PHP 实现 CommonJS Promises/A 的库。
它还提供了其他几个有用的与 Promise 相关的概念,例如连接多个 Promise 以及映射和减少 Promise 集合。
如果您以前从未听说过 Promise,请先阅读本文。
延迟表示可能尚未完成的计算或工作单元。通常(但并非总是),该计算将异步执行并在将来的某个时刻完成。
deferred 代表计算本身,而Promise 则代表该计算的结果。因此,每个 deferred 都有一个 Promise,充当其实际结果的占位符。
延迟表示其决议待决的操作。它有单独的承诺和解析器部分。
$ deferred = new React Promise Deferred ();
$ promise = $ deferred -> promise ();
$ deferred -> resolve (mixed $ value );
$ deferred -> reject (Throwable $ reason );
promise
方法返回延迟的 Promise。
resolve
方法和reject
方法控制延迟的状态。
Deferred
的构造函数接受可选的$canceller
参数。请参阅 Promise 了解更多信息。
$ promise = $ deferred -> promise ();
返回延迟的承诺,您可以将其分发给其他人,同时保留修改其状态的权限给您自己。
$ deferred -> resolve (mixed $ value );
解析由promise()
返回的promise。通过使用$value
调用$onFulfilled
(他们通过$promise->then()
注册)来通知所有消费者。
如果$value
本身是一个promise,那么一旦resolved,promise就会转换到这个promise的状态。
另请参见resolve()
函数。
$ deferred -> reject (Throwable $ reason );
拒绝由promise()
返回的 Promise,表明 deferred 的计算失败。通过使用$reason
调用$onRejected
(他们通过$promise->then()
注册)来通知所有消费者。
另请参见reject()
函数。
Promise 接口为所有 Promise 实现提供通用接口。请参阅 Promise 了解此包公开的唯一公共实现。
承诺代表最终结果,要么是实现(成功)和相关的值,要么是拒绝(失败)和相关的原因。
一旦处于履行或拒绝状态,承诺就变得不可变。它的状态和结果(或错误)都不能被修改。
$ transformedPromise = $ promise -> then (callable $ onFulfilled = null , callable $ onRejected = null );
通过将函数应用于承诺的履行或拒绝值来转换承诺的值。返回转换结果的新承诺。
then()
方法使用 Promise 注册新的已完成和拒绝处理程序(所有参数都是可选的):
$onFulfilled
将被调用。$onRejected
将被调用。它返回一个新的 Promise,该 Promise 将通过$onFulfilled
或$onRejected
(无论调用哪个)的返回值来实现,或者如果抛出异常,则将拒绝并抛出异常。
Promise 对在对then()
同一调用中注册的处理程序做出以下保证:
$onFulfilled
或$onRejected
之一,而不会同时调用两者。$onFulfilled
和$onRejected
永远不会被多次调用。 $ promise -> catch (callable $ onRejected );
为 Promise 注册拒绝处理程序。它是以下功能的快捷方式:
$ promise -> then ( null , $ onRejected );
此外,您可以键入提示$onRejected
的$reason
参数以仅捕获特定错误。
$ promise
-> catch ( function ( RuntimeException $ reason ) {
// Only catch RuntimeException instances
// All other types of errors will propagate automatically
})
-> catch ( function ( Throwable $ reason ) {
// Catch other errors
});
$ newPromise = $ promise -> finally (callable $ onFulfilledOrRejected );
允许您在承诺链中执行“清理”类型的任务。
当承诺被履行或被拒绝时,它安排调用$onFulfilledOrRejected
,不带任何参数。
$promise
履行,并且$onFulfilledOrRejected
成功返回, $newPromise
将履行与$promise
相同的值。$promise
满足,并且$onFulfilledOrRejected
抛出或返回拒绝的 Promise,则$newPromise
将拒绝并抛出异常或拒绝 Promise 的原因。$promise
拒绝,并且$onFulfilledOrRejected
成功返回,则$newPromise
将拒绝,原因与$promise
相同。$promise
拒绝,并且$onFulfilledOrRejected
抛出或返回拒绝的 Promise,则$newPromise
将拒绝并抛出异常或拒绝 Promise 的原因。 finally()
行为与同步finally 语句类似。当与catch()
结合使用时, finally()
允许您编写类似于熟悉的同步 catch/finally 对的代码。
考虑以下同步代码:
try {
return doSomething ();
} catch ( Throwable $ e ) {
return handleError ( $ e );
} finally {
cleanup ();
}
可以编写类似的异步代码(使用返回 Promise 的doSomething()
):
return doSomething ()
-> catch ( ' handleError ' )
-> finally ( ' cleanup ' );
$ promise -> cancel ();
cancel()
方法通知 Promise 的创建者不再对操作结果感兴趣。
一旦 Promise 被解决(履行或拒绝),对 Promise 调用cancel()
就不会产生任何效果。
自 v3.0.0 起已弃用,请参阅
catch()
。
otherwise()
方法为 Promise 注册拒绝处理程序。
此方法继续存在只是出于 BC 原因并简化版本之间的升级。它是以下的别名:
$ promise -> catch ( $ onRejected );
自 v3.0.0 起已弃用,请参阅
finally()
。
always()
方法允许您在承诺链中执行“清理”类型的任务。
此方法继续存在只是出于 BC 原因并简化版本之间的升级。它是以下的别名:
$ promise -> finally ( $ onFulfilledOrRejected );
创建一个 Promise,其状态由传递给$resolver
函数控制。
$ resolver = function ( callable $ resolve , callable $ reject ) {
// Do some work, possibly asynchronously, and then
// resolve or reject.
$ resolve ( $ awesomeResult );
// or throw new Exception('Promise rejected');
// or $resolve($anotherPromise);
// or $reject($nastyError);
};
$ canceller = function () {
// Cancel/abort any running operations like network connections, streams etc.
// Reject promise by throwing an exception
throw new Exception ( ' Promise cancelled ' );
};
$ promise = new React Promise Promise ( $ resolver , $ canceller );
Promise 构造函数接收一个解析器函数和一个可选的取消器函数,这两个函数都将使用两个参数调用:
$resolve($value)
- 决定返回的 Promise 命运的主要函数。接受非承诺值或另一个承诺。当使用非承诺值调用时,用该值履行承诺。当使用另一个 Promise 调用时,例如$resolve($otherPromise)
, Promise 的命运将与$otherPromise
的命运相同。$reject($reason)
- 拒绝承诺的函数。建议仅抛出异常而不是使用$reject()
。如果解析器或取消器抛出异常,则 Promise 将被拒绝,并以抛出的异常作为拒绝原因。
解析器函数将立即被调用,而取消器函数只有在所有消费者调用 Promise 的cancel()
方法时才会被调用。
用于创建和加入承诺集合的有用函数。
所有作用于 Promise 集合的函数(如all()
、 race()
等)都支持取消。这意味着,如果您对返回的 Promise 调用cancel()
,则集合中的所有 Promise 都将被取消。
$ promise = React Promise resolve (mixed $ promiseOrValue );
为提供的$promiseOrValue
创建承诺。
如果$promiseOrValue
是一个值,它将是返回的 Promise 的解析值。
如果$promiseOrValue
是 thenable(任何提供then()
方法的对象),则返回遵循 thenable 状态的可信 Promise。
如果$promiseOrValue
是一个承诺,它将按原样返回。
生成的$promise
实现了PromiseInterface
并且可以像任何其他 Promise 一样使用:
$ promise = React Promise resolve ( 42 );
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
$ promise = React Promise reject (Throwable $ reason );
为提供的$reason
创建拒绝的承诺。
请注意,PHP 7 中引入的Throwable
接口涵盖了用户态Exception
和Error
内部 PHP 错误。通过强制使用Throwable
作为拒绝承诺的理由,任何语言错误或用户域异常都可以用来拒绝承诺。
生成的$promise
实现了PromiseInterface
并且可以像任何其他 Promise 一样使用:
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
请注意,被拒绝的 Promise 的处理方式应始终类似于在try
+ catch
块中捕获异常的方式。如果删除对尚未处理的被拒绝的 Promise 的最后一个引用,它将报告未处理的 Promise 拒绝:
function incorrect (): int
{
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
// Commented out: No rejection handler registered here.
// $promise->then(null, function (Throwable $e): void { /* ignore */ });
// Returning from a function will remove all local variable references, hence why
// this will report an unhandled promise rejection here.
return 42 ;
}
// Calling this function will log an error message plus its stack trace:
// Unhandled promise rejection with RuntimeException: Request failed in example.php:10
incorrect ();
如果您使用then()
方法、 catch()
方法或finally()
方法捕获拒绝原因,则被拒绝的 Promise 将被视为“已处理”。请注意,这些方法中的每一个都会返回一个新的 Promise,如果您重新抛出异常,该 Promise 可能会再次被拒绝。
如果您使用cancel()
方法中止操作,则被拒绝的 Promise 也将被视为“已处理”(如果 Promise 仍处于挂起状态,则通常会拒绝该 Promise)。
另请参见set_rejection_handler()
函数。
$ promise = React Promise all (iterable $ promisesOrValues );
返回一个只有在$promisesOrValues
中的所有项目都已解决后才会解决的承诺。返回的 Promise 的分辨率值将是一个数组,其中包含$promisesOrValues
中每个项目的分辨率值。
$ promise = React Promise race (iterable $ promisesOrValues );
发起一场竞赛,选出一名获胜者。返回一个 Promise,其解决方式与第一个已解决的 Promise 的解决方式相同。
如果$promisesOrValues
包含 0 个项目,则返回的 Promise 将无限期挂起。
$ promise = React Promise any (iterable $ promisesOrValues );
返回一个承诺,当$promisesOrValues
中的任何一项解决时,该承诺将得到解决。返回的 Promise 的解析值将是触发项的解析值。
仅当$promisesOrValues
中的所有项目都被拒绝时,返回的 Promise 才会被拒绝。拒绝值将是一个ReactPromiseExceptionCompositeException
,其中包含所有拒绝原因。可以使用CompositeException::getThrowables()
获取拒绝原因。
如果$promisesOrValues
包含 0 个项目,则返回的 Promise 也将拒绝并返回ReactPromiseExceptionLengthException
。
React Promise set_rejection_handler(?callable $ callback ): ?callable;
为未处理的承诺拒绝设置全局拒绝处理程序。
请注意,被拒绝的 Promise 的处理方式应始终类似于在try
+ catch
块中捕获异常的方式。如果您删除对尚未处理的被拒绝的承诺的最后一个引用,它将报告未处理的承诺拒绝。另请参阅reject()
函数以了解更多详细信息。
?callable $callback
参数必须是一个有效的回调函数,它接受单个Throwable
参数或null
值来恢复默认的 Promise 拒绝处理程序。回调函数的返回值将被忽略并且没有任何作用,因此您应该返回一个void
值。回调函数不得抛出异常,否则程序将因致命错误而终止。
该函数返回先前的拒绝处理程序,如果使用默认的承诺拒绝处理程序,则返回null
。
默认的承诺拒绝处理程序将记录错误消息及其堆栈跟踪:
// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
React Promise reject ( new RuntimeException ( ' Unhandled ' ));
承诺拒绝处理程序可用于自定义日志消息或写入自定义日志目标。根据经验,此函数只能用作最后的手段,并且最好使用then()
方法、 catch()
方法或finally()
方法来处理 Promise 拒绝。另请参阅reject()
函数以了解更多详细信息。
function getAwesomeResultPromise ()
{
$ deferred = new React Promise Deferred ();
// Execute a Node.js-style function using the callback pattern
computeAwesomeResultAsynchronously ( function ( Throwable $ error , $ result ) use ( $ deferred ) {
if ( $ error ) {
$ deferred -> reject ( $ error );
} else {
$ deferred -> resolve ( $ result );
}
});
// Return the promise
return $ deferred -> promise ();
}
getAwesomeResultPromise ()
-> then (
function ( $ value ) {
// Deferred resolved, do something with $value
},
function ( Throwable $ reason ) {
// Deferred rejected, do something with $reason
}
);
几个简单的例子展示了 Promises/A 转发的机制是如何工作的。当然,这些示例是人为设计的,在实际使用中,承诺链通常会分布在多个函数调用中,甚至分布在应用程序架构的多个级别上。
已解决的承诺将解决值转发到下一个承诺。第一个 Promise $deferred->promise()
将使用传递给下面的$deferred->resolve()
的值进行解析。
每次调用then()
都会返回一个新的 Promise,该 Promise 将使用前一个处理程序的返回值进行解析。这创建了一个承诺“管道”。
$ deferred = new React Promise 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 类似,并且工作方式也与 try/catch 类似:当捕获异常时,必须重新抛出异常才能传播。
类似地,当您处理被拒绝的 Promise 时,要传播拒绝,请通过返回被拒绝的 Promise 或实际抛出来“重新抛出”它(因为 Promise 将抛出的异常转换为拒绝)
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Propagate the rejection
throw $ x ;
})
-> catch ( function ( Exception $ x ) {
// Can also propagate by returning another rejection
return React Promise reject (
new Exception ( $ x -> getMessage () + 1 )
);
})
-> catch ( function ( $ x ) {
echo ' Reject ' . $ x -> getMessage (); // 3
});
$ deferred -> resolve ( 1 ); // Prints "Reject 3"
就像try/catch一样,你可以选择传播或不传播。混合解决方案和拒绝仍将以可预测的方式转发处理程序结果。
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
return $ x + 1 ;
})
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Handle the rejection, and don't propagate.
// This is like catch without a rethrow
return $ x -> getMessage () + 1 ;
})
-> then ( function ( $ x ) {
echo ' Mixed ' . $ x ; // 4
});
$ deferred -> resolve ( 1 ); // Prints "Mixed 4"
推荐的安装此库的方法是通过 Composer。作曲家新手?
该项目遵循 SemVer。这将从该分支安装最新支持的版本:
composer require react/promise:^3.2
有关版本升级的详细信息,另请参阅变更日志。
该项目旨在在任何平台上运行,因此不需要任何 PHP 扩展,并支持在 PHP 7.1 到当前 PHP 8+ 上运行。强烈建议为此项目使用最新支持的 PHP 版本。
我们致力于提供长期支持 (LTS) 选项并提供顺畅的升级路径。如果您使用的是较旧的 PHP 版本,则可以使用2.x
分支 (PHP 5.4+) 或1.x
分支 (PHP 5.3+),它们都提供兼容的 API,但不利用较新的语言功能。您可以同时定位多个版本以支持更广泛的 PHP 版本,如下所示:
composer require " react/promise:^3 || ^2 || ^1 "
要运行测试套件,您首先需要克隆此存储库,然后通过 Composer 安装所有依赖项:
composer install
要运行测试套件,请转到项目根目录并运行:
vendor/bin/phpunit
除此之外,我们在最大级别上使用 PHPStan 以确保整个项目的类型安全:
vendor/bin/phpstan
Promise 是 Brian Cavalier 对when.js 的移植。
此外,大部分文档都是从when.js Wiki 和 API 文档移植的。
根据麻省理工学院许可发布。