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 類似:捕獲異常時,必須重新拋出異常才能傳播。
類似地,當您處理被拒絕的 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 文件移植。
根據麻省理工學院許可發布。