From 44bc9715d608956c813994d8b1b2198c668a4235 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 23 Dec 2016 22:26:05 +0100 Subject: [PATCH] Fix Promise::when invocation order --- lib/Internal/Placeholder.php | 39 ++++++++++++++++++------------------ test/WhenOrderTest.php | 30 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 test/WhenOrderTest.php diff --git a/lib/Internal/Placeholder.php b/lib/Internal/Placeholder.php index 2c5a06eb..346a0eae 100644 --- a/lib/Internal/Placeholder.php +++ b/lib/Internal/Placeholder.php @@ -17,10 +17,10 @@ trait Placeholder { /** @var mixed */ private $result; - + /** @var callable|\Amp\Internal\WhenQueue|null */ private $onResolved; - + /** * @see \Interop\Async\Promise::when() */ @@ -63,27 +63,28 @@ private function resolve($value = null) { throw new \Error("Promise has already been resolved"); } - $this->resolved = true; $this->result = $value; - if ($this->onResolved === null) { - return; - } + try { + while ($this->onResolved !== null) { + $onResolved = $this->onResolved; + $this->onResolved = null; - $onResolved = $this->onResolved; - $this->onResolved = null; + if ($this->result instanceof Promise) { + $this->result->when($onResolved); + return; + } - if ($this->result instanceof Promise) { - $this->result->when($onResolved); - return; - } - - try { - $onResolved(null, $this->result); - } catch (\Throwable $exception) { - Loop::defer(static function () use ($exception) { - throw $exception; - }); + try { + $onResolved(null, $this->result); + } catch (\Throwable $exception) { + Loop::defer(static function () use ($exception) { + throw $exception; + }); + } + } + } finally { + $this->resolved = true; } } diff --git a/test/WhenOrderTest.php b/test/WhenOrderTest.php new file mode 100644 index 00000000..9ffea938 --- /dev/null +++ b/test/WhenOrderTest.php @@ -0,0 +1,30 @@ +expectOutputString("1234"); + + $deferred = new Deferred; + $promise = $deferred->promise(); + + $promise->when(function () use ($promise) { + $promise->when(function () { + printf("%d", 3); + }); + printf("%d", 1); + }); + + $promise->when(function () use ($promise) { + $promise->when(function () { + printf("%d", 4); + }); + printf("%d", 2); + }); + + $deferred->resolve(); + } +}