摘要:結果打印我結論或問題這里我們基礎實現了一個可以用于生產環境的后續我們會接續完善這個的特有方法,比如等后續再介紹用實現的自動執行器等附錄參考中文對象入門阮一峰
PHP下的異步嘗試系列
如果你還不太了解PHP下的生成器和協程,你可以根據下面目錄翻閱
PHP下的異步嘗試一:初識生成器
PHP下的異步嘗試二:初識協程
PHP下的異步嘗試三:協程的PHP版thunkify自動執行器
PHP下的異步嘗試四:PHP版的Promise
PHP下的異步嘗試五:PHP版的Promise的繼續完善
Promise 實現 代碼結構│ │ autoload.php │ │ promise1.php │ │ promise2.php │ │ promise3.php │ │ promise4.php │ │ promise5.php │ │ │ └─classes │ Promise1.php │ Promise2.php │ Promise3.php │ Promise4.php │ Promise5.php │ PromiseState.php嘗試一 (Promise基礎)
classess/PromiseState.php
final class PromiseState { const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; }
classess/Promise1.php
// 嘗試一 class Promise1 { private $value; private $reason; private $state; public function __construct(Closure $func = null) { $this->state = PromiseState::PENDING; $func([$this, "resolve"], [$this, "reject"]); } /** * 執行回調方法里的resolve綁定的方法 * @param null $value */ public function resolve($value = null) { // 回調執行resolve傳參的值,賦值給result $this->value = $value; if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::FULFILLED; } } public function reject($reason = null) { // 回調執行resolve傳參的值,賦值給result $this->reason = $reason; if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::REJECTED; } } public function getState() { return $this->state; } public function getValue() { return $this->value; } public function getReason() { return $this->reason; } }
promise1.php
require "autoload.php"; $promise = new Promise1(function($resolve, $reject) { $resolve("打印我"); }); var_dump($promise->getState()); var_dump($promise->getValue());結果:
string(9) "fulfilled" string(9) "打印我"結論或問題:
我們在這里建構了最基礎的Promise模型嘗試二 (增加鏈式then)
classess/Promise2.php
state = PromiseState::PENDING; $func([$this, "resolve"], [$this, "reject"]); } public function then(Closure $onFulfilled = null, Closure $onRejected = null) { // 如果狀態是fulfilled,直接回調執行并傳參value if ($this->state == PromiseState::FULFILLED) { $onFulfilled($this->value); } // 如果狀態是rejected,直接回調執行并傳參reason if ($this->state == PromiseState::REJECTED) { $onRejected($this->reason); } // 返回對象自身,實現鏈式調用 return $this; } /** * 執行回調方法里的resolve綁定的方法 * 本狀態只能從pending->fulfilled * @param null $value */ public function resolve($value = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::FULFILLED; $this->value = $value; } } /** * 執行回調方法里的rejected綁定的方法 * 本狀態只能從pending->rejected * @param null $reason */ public function reject($reason = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::REJECTED; $this->reason = $reason; } } public function getState() { return $this->state; } public function getValue() { return $this->value; } public function getReason() { return $this->reason; } }
promise2.php
then(function ($value) { var_dump($value); }, function ($reason) { var_dump($reason); })->then(function ($value) { var_dump($value); }, function ($reason) { var_dump($reason); });結果:
string(9) "打印我" string(9) "打印我"結論或問題:
我們實現了鏈式then方法 如果我們的構造里的回調是異步執行的話,那么狀態在沒有變成fulfilled之前,我們then里的回調方法就永遠沒法執行嘗試三(真正的鏈式then)
classess/Promise3.php
// 解決思路:我們肯定要把then傳入的回調,放到Promise構造里回調代碼執行完后resolve調用后改變了state狀態后再調用,所以我們必須存儲到一個地方并方便后續調用 // 我們需要改造then、resolve和reject方法 class Promise3 { private $value; private $reason; private $state; private $fulfilledCallbacks = []; private $rejectedCallbacks = []; public function __construct(Closure $func = null) { $this->state = PromiseState::PENDING; $func([$this, "resolve"], [$this, "reject"]); } public function then(Closure $onFulfilled = null, Closure $onRejected = null) { // 如果是異步回調,狀態未變化之前,then的回調方法壓入相應的數組方便后續調用 if ($this->state == PromiseState::PENDING) { $this->fulfilledCallbacks[] = static function() use ($onFulfilled, $value){ $onFulfilled($this->value); }; $this->rejectedCallbacks[] = static function() use ($onRejected, $reason){ $onRejected($this->reason); }; } // 如果狀態是fulfilled,直接回調執行并傳參value if ($this->state == PromiseState::FULFILLED) { $onFulfilled($this->value); } // 如果狀態是rejected,直接回調執行并傳參reason if ($this->state == PromiseState::REJECTED) { $onRejected($this->reason); } // 返回對象自身,實現鏈式調用 return $this; } /** * 執行回調方法里的resolve綁定的方法 * 本狀態只能從pending->fulfilled * @param null $value */ public function resolve($value = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::FULFILLED; $this->value = $value; array_walk($this->fulfilledCallbacks, function ($callback) { $callback(); }); } } /** * 執行回調方法里的rejected綁定的方法 * 本狀態只能從pending->rejected * @param null $reason */ public function reject($reason = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::REJECTED; $this->reason = $reason; } } public function getState() { return $this->state; } public function getValue() { return $this->value; } public function getReason() { return $this->reason; } }
promise3.php
require "autoload.php"; $promise = new Promise3(function($resolve, $reject) { $resolve("打印我"); }); $promise->then(function ($value) { var_dump($value); }, function ($reason) { var_dump($reason); })->then(function ($value) { var_dump($value); }, function ($reason) { var_dump($reason); });結果:
string(9) "打印我" string(9) "打印我"結論或問題:
我們這次基本實現了真正的鏈式then方法 不過在Promise/A+里規范,要求then返回每次都要求是一個新的Promise對象 then方法成功執行,相當于返回一個實例一個Promise回調里執行resolve方法,resolve值為then里return的值 then方法執行失敗或出錯,相當于返回一個實例一個Promise回調里執行rejected方法,rejected值為then里return的值嘗試四(then返回pormise對象, 并傳遞上一次的結果給下一個Promise對象)
classess/Promise4.php
class Promise4 { private $value; private $reason; private $state; private $fulfilledCallbacks = []; private $rejectedCallbacks = []; public function __construct(Closure $func = null) { $this->state = PromiseState::PENDING; $func([$this, "resolve"], [$this, "reject"]); } public function then(Closure $onFulfilled = null, Closure $onRejected = null) { $thenPromise = new Promise4(function ($reslove, $reject) use (&$thenPromise, $onFulfilled, $onRejected) { //$this 代表的當前的Promise對象,不要混淆了 // 如果是異步回調,狀態未變化之前,then的回調方法壓入相應的數組方便后續調用 if ($this->state == PromiseState::PENDING) { $this->fulfilledCallbacks[] = static function() use ($thenPromise, $onFulfilled, $reslove, $reject){ $value = $onFulfilled($this->value); $this->resolvePromise($thenPromise, $value, $reslove, $reject); }; $this->rejectedCallbacks[] = static function() use ($thenPromise, $onRejected, $reslove, $reject){ $reason = $onRejected($this->reason); $this->resolvePromise($thenPromise, $reason, $reslove, $reject); }; } // 如果狀態是fulfilled,直接回調執行并傳參value if ($this->state == PromiseState::FULFILLED) { $value = $onFulfilled($this->value); $this->resolvePromise($thenPromise, $value, $reslove, $reject); } // 如果狀態是rejected,直接回調執行并傳參reason if ($this->state == PromiseState::REJECTED) { $reason = $onRejected($this->reason); $this->resolvePromise($thenPromise, $reason, $reslove, $reject); } }); // 返回對象自身,實現鏈式調用 return $thenPromise; } /** * 解決Pormise鏈式then傳遞 * 可參考 [Promises/A+]2.3 [https://promisesaplus.com/#the-promise-resolution-procedure] * @param $thenPromise * @param $x $x為thenable對象 * @param $resolve * @param $reject */ private function resolvePromise($thenPromise, $x, $resolve, $reject) { $called = false; if ($thenPromise === $x) { return $reject(new Exception("循環引用")); } if ( is_object($x) && method_exists($x, "then")) { $resolveCb = function ($value) use($thenPromise, $resolve, $reject, $called) { if ($called) return ; $called = true; // 成功值y有可能還是promise或者是具有then方法等,再次resolvePromise,直到成功值為基本類型或者非thenable $this->resolvePromise($thenPromise, $value, $resolve, $reject); }; $rejectCb = function($reason) use($thenPromise, $resolve, $reject, $called) { if ($called) return ; $called = true; $reject($reason); }; call_user_func_array([$x, "then"], [$resolveCb, $rejectCb]); } else { if ($called) return ; $called = true; $resolve($x); } } /** * 執行回調方法里的resolve綁定的方法 * 本狀態只能從pending->fulfilled * @param null $value */ public function resolve($value = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::FULFILLED; $this->value = $value; array_walk($this->fulfilledCallbacks, function ($callback) { $callback(); }); } } /** * 執行回調方法里的rejected綁定的方法 * 本狀態只能從pending->rejected * @param null $reason */ public function reject($reason = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::REJECTED; $this->reason = $reason; } } public function getState() { return $this->state; } public function getValue() { return $this->value; } public function getReason() { return $this->reason; } }
promise4.php
require "autoload.php"; $promise1 = new Promise4(function($resolve, $reject) { $resolve("打印我"); }); $promise2 = $promise1->then(function ($value) { var_dump($value); return "promise2"; }, function ($reason) { var_dump($reason); }); $promise3 = $promise2->then(function ($value) { var_dump($value); return new Promise4(function($resolve, $reject) { $resolve("promise3"); }); }, function ($reason) { var_dump($reason); }); $promise4 = $promise3->then(function ($value) { var_dump($value); return "promise4"; }, function ($reason) { var_dump($reason); }); var_dump($promise4);結果:
string(9) "打印我" string(8) "promise2" string(8) "promise3" object(Promise4)#15 (5) { ["value":"Promise4":private]=> string(8) "promise4" ["reason":"Promise4":private]=> NULL ["state":"Promise4":private]=> string(9) "fulfilled" ["fulfilledCallbacks":"Promise4":private]=> array(0) { } ["rejectedCallbacks":"Promise4":private]=> array(0) { } }結論或問題:
一個基本的Pormise,不過我們上面都是基于成功fulfilled狀態的實現 下面我們來增加錯誤捕獲嘗試五(錯誤捕獲)
classess/Promise5.php
class Promise5 { private $value; private $reason; private $state; private $fulfilledCallbacks = []; private $rejectedCallbacks = []; public function __construct(Closure $func = null) { $this->state = PromiseState::PENDING; $func([$this, "resolve"], [$this, "reject"]); } public function then(Closure $onFulfilled = null, Closure $onRejected = null) { // 此處作用是兼容then方法的以下四種參數變化,catchError就是第二種情況 // 1. then($onFulfilled, null) // 2. then(null, $onRejected) // 3. then(null, null) // 4. then($onFulfilled, $onRejected) $onFulfilled = is_callable($onFulfilled) ? $onFulfilled : function ($value) {return $value;}; $onRejected = is_callable($onRejected) ? $onRejected : function ($reason) {throw $reason;}; $thenPromise = new Promise5(function ($reslove, $reject) use (&$thenPromise, $onFulfilled, $onRejected) { //$this 代表的當前的Promise對象,不要混淆了 // 如果是異步回調,狀態未變化之前,then的回調方法壓入相應的數組方便后續調用 if ($this->state == PromiseState::PENDING) { $this->fulfilledCallbacks[] = static function() use ($thenPromise, $onFulfilled, $reslove, $reject){ try { $value = $onFulfilled($this->value); $this->resolvePromise($thenPromise, $value, $reslove, $reject); } catch (Exception $e) { $reject($e); } }; $this->rejectedCallbacks[] = static function() use ($thenPromise, $onRejected, $reslove, $reject){ try { $reason = $onRejected($this->reason); $this->resolvePromise($thenPromise, $reason, $reslove, $reject); } catch (Exception $e) { $reject($e); } }; } // 如果狀態是fulfilled,直接回調執行并傳參value if ($this->state == PromiseState::FULFILLED) { try { $value = $onFulfilled($this->value); $this->resolvePromise($thenPromise, $value, $reslove, $reject); } catch (Exception $e) { $reject($e); } } // 如果狀態是rejected,直接回調執行并傳參reason if ($this->state == PromiseState::REJECTED) { try { $reason = $onRejected($this->reason); $this->resolvePromise($thenPromise, $reason, $reslove, $reject); } catch (Exception $e) { $reject($e); } } }); // 返回對象自身,實現鏈式調用 return $thenPromise; } public function catchError($onRejected) { return $this->then(null, $onRejected); } /** * 解決Pormise鏈式then傳遞 * 可參考 [Promises/A+]2.3 [https://promisesaplus.com/#the-promise-resolution-procedure] * @param $thenPromise * @param $x $x為thenable對象 * @param $resolve * @param $reject */ private function resolvePromise($thenPromise, $x, $resolve, $reject) { $called = false; if ($thenPromise === $x) { return $reject(new Exception("循環引用")); } if ( is_object($x) && method_exists($x, "then")) { try { $resolveCb = function ($value) use ($thenPromise, $resolve, $reject, $called) { if ($called) return; $called = true; // 成功值y有可能還是promise或者是具有then方法等,再次resolvePromise,直到成功值為基本類型或者非thenable $this->resolvePromise($thenPromise, $value, $resolve, $reject); }; $rejectCb = function ($reason) use ($thenPromise, $resolve, $reject, $called) { if ($called) return; $called = true; $reject($reason); }; call_user_func_array([$x, "then"], [$resolveCb, $rejectCb]); } catch (Exception $e) { if ($called) return ; $called = true; $reject($e); } } else { if ($called) return ; $called = true; $resolve($x); } } /** * 執行回調方法里的resolve綁定的方法 * 本狀態只能從pending->fulfilled * @param null $value */ public function resolve($value = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::FULFILLED; $this->value = $value; array_walk($this->fulfilledCallbacks, function ($callback) { $callback(); //因為回調本身攜帶了作用于,所以直接調用,無法參數 }); } } /** * 執行回調方法里的rejected綁定的方法 * 本狀態只能從pending->rejected * @param null $reason */ public function reject($reason = null) { if ($this->state == PromiseState::PENDING) { $this->state = PromiseState::REJECTED; $this->reason = $reason; array_walk($this->rejectedCallbacks, function ($callback) { $callback(); //因為回調本身攜帶了作用于,所以直接調用,無法參數 }); } } public function getState() { return $this->state; } public function getValue() { return $this->value; } public function getReason() { return $this->reason; } }
promise5.php
require "autoload.php"; $promise1 = new Promise5(function($resolve, $reject) { $resolve("打印我"); }); $promise2 = $promise1->then(function ($value) { var_dump($value); throw new Exception("promise2 error"); return "promise2"; }, function ($reason) { var_dump($reason->getMessage()); return "promise3 error return"; }); //我們可以簡寫then方法,只傳入$onFulfilled方法,然后錯誤會自己冒泡方式到下一個catchError或then里處理。 //$promise3 = $promise2->then(function ($value) { // var_dump($value); // return new Promise5(function($resolve, $reject) { // $resolve("promise3"); // }); //})->catchError(function ($reason) { // var_dump($reason->getMessage()); // return "promise3 error return"; //}); $promise3 = $promise2->then(function ($value) { var_dump($value); return new Promise5(function($resolve, $reject) { $resolve("promise3"); }); }, function ($reason) { var_dump($reason->getMessage()); return "promise3 error return"; }); $promise4 = $promise3->then(function ($value) { var_dump($value); return "promise4"; }, function ($reason) { echo $reason->getMessage(); }); var_dump($promise4);結果:
string(9) "打印我" string(14) "promise2 error" string(21) "promise3 error return" object(Promise4)#10 (5) { ["value":"Promise4":private]=> string(8) "promise4" ["reason":"Promise4":private]=> NULL ["state":"Promise4":private]=> string(9) "fulfilled" ["fulfilledCallbacks":"Promise4":private]=> array(0) { } ["rejectedCallbacks":"Promise4":private]=> array(0) { } }結論或問題:
這里我們基礎實現了一個可以用于生產環境的Promise 后續我們會接續完善這個Promise的特有方法,比如:finally, all, race, resolve, reject等 后續再介紹用Promise實現的自動執行器等附錄參考
Promises/A+
Promises/A+ 中文
Promise 對象 - ECMAScript 6 入門 阮一峰
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/29463.html
摘要:如果僅依靠程序自動交出控制的話,那么一些惡意程序將會很容易占用全部時間而不與其他任務共享。多個操作可以在重疊的時間段內進行。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器,你可以根據下面目錄翻閱 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協程 PHP下的異步嘗試三:協程的PHP版thunkify自動執行器 PHP下的異步嘗試四:PHP版的Promise ...
摘要:函數并不是生成器協程函數自動執行的唯一方案。因為自動執行的關鍵是,必須有一種機制,自動控制生成器協程函數的流程,接收和交還程序的執行權?;卣{函數可以做到這一點,對象也可以做到這一點。本系列的下一篇,將介紹基于的實現的自動執行器。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器和協程,你可以根據下面目錄翻閱 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協程 P...
摘要:下的異步嘗試系列下的異步嘗試一初識生成器下的異步嘗試二初識協程下的異步嘗試三協程的版自動執行器下的異步嘗試四版的下的異步嘗試五版的的繼續完善生成器類獲取迭代器當前值獲取迭代器當前值返回當前產生的鍵生成器從上一次處繼續執行重置迭代器向生成器中 PHP下的異步嘗試系列 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協程 PHP下的異步嘗試三:協程的PHP版thunkify自...
摘要:四異步編程解決方案模式模式一定程度上緩解了嵌套回調的問題,只會處在未完成完成態失敗態中的一種,只會從未完成轉化為完成態或者失敗態,不能逆轉。 一、從一個簡單的案例開始 fs.readdir(path.join(__dirname, ./index.js), (err, files) => { files.foreach((filename, index) => { ...
閱讀 766·2023-04-25 17:33
閱讀 3626·2021-07-29 14:49
閱讀 2480·2019-08-30 15:53
閱讀 3435·2019-08-29 16:27
閱讀 2000·2019-08-29 16:11
閱讀 1030·2019-08-29 14:17
閱讀 2432·2019-08-29 13:47
閱讀 2016·2019-08-29 13:28