Skip to content

Commit 56b0f04

Browse files
author
Jeremiah VALERIE
committed
Optimize DataLoader::await method
`DataLoader::await` first tries to get the fulfilled value or the rejected reason directly from the promise otherwise calls promise adapter `await` to complete promise. Now `DataLoader::await` will not throw "no active dataLoader instance" exception when Promise entry is null.
1 parent 0387742 commit 56b0f04

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

src/DataLoader.php

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,21 +239,55 @@ protected function getPromiseAdapter()
239239
*/
240240
public static function await($promise = null, $unwrap = true)
241241
{
242+
self::awaitInstances();
243+
244+
if (null === $promise) {
245+
return null;
246+
}
247+
248+
if (is_callable([$promise, 'then'])) {
249+
$isPromiseCompleted = false;
250+
$resolvedValue = null;
251+
$rejectedReason = null;
252+
253+
$promise->then(
254+
function ($value) use (&$isPromiseCompleted, &$resolvedValue) {
255+
$isPromiseCompleted = true;
256+
$resolvedValue = $value;
257+
},
258+
function ($reason) use (&$isPromiseCompleted, &$rejectedReason) {
259+
$isPromiseCompleted = true;
260+
$rejectedReason = $reason;
261+
}
262+
);
263+
264+
//Promise is completed?
265+
if ($isPromiseCompleted) {
266+
// rejected ?
267+
if ($rejectedReason instanceof \Exception) {
268+
if (!$unwrap) {
269+
return $rejectedReason;
270+
}
271+
throw $rejectedReason;
272+
}
273+
274+
return $resolvedValue;
275+
}
276+
}
277+
242278
if (empty(self::$instances)) {
243279
throw new \RuntimeException('Found no active DataLoader instance.');
244280
}
245-
self::awaitInstances();
246281

247282
return self::$instances[0]->getPromiseAdapter()->await($promise, $unwrap);
248283
}
249284

250285
private static function awaitInstances()
251286
{
252-
$dataLoaders = self::$instances;
287+
do {
288+
$wait = false;
289+
$dataLoaders = self::$instances;
253290

254-
$wait = true;
255-
256-
while ($wait) {
257291
foreach ($dataLoaders as $dataLoader) {
258292
if (!$dataLoader || !$dataLoader->needProcess()) {
259293
$wait = false;
@@ -262,12 +296,7 @@ private static function awaitInstances()
262296
$wait = true;
263297
$dataLoader->process();
264298
}
265-
}
266-
267-
// If new dataloaders were instanciated in the meantime, wait again !
268-
if (count($dataLoaders) != count(self::$instances)) {
269-
self::awaitInstances();
270-
}
299+
} while ($wait);
271300
}
272301

273302
/**

tests/AbuseTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function testAwaitPromiseMustHaveAThenMethod()
111111
*/
112112
public function testAwaitWithoutNoInstance()
113113
{
114-
DataLoader::await();
114+
DataLoader::await(self::$promiseAdapter->create());
115115
}
116116

117117
/**

tests/DataLoadTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,38 @@ public function testAwaitAlsoAwaitsNewlyCreatedDataloaders()
809809
$this->assertTrue($secondComplete);
810810
}
811811

812+
/**
813+
* @runInSeparateProcess
814+
*/
815+
public function testAwaitShouldReturnTheValueOfFulfilledPromiseWithoutNeedingActiveDataLoaderInstance()
816+
{
817+
$expectedValue = 'Ok!';
818+
$value = DataLoader::await(self::$promiseAdapter->createFulfilled($expectedValue));
819+
820+
$this->assertEquals($expectedValue, $value);
821+
}
822+
823+
/**
824+
* @runInSeparateProcess
825+
*/
826+
public function testAwaitShouldReturnTheRejectReasonOfRejectedPromiseWithoutNeedingActiveDataLoaderInstance()
827+
{
828+
$expectedException = new \Exception('Rejected!');
829+
$exception = DataLoader::await(self::$promiseAdapter->createRejected($expectedException), false);
830+
831+
$this->assertEquals($expectedException, $exception);
832+
}
833+
834+
/**
835+
* @expectedException \Exception
836+
* @expectedExceptionMessage Rejected!
837+
* @runInSeparateProcess
838+
*/
839+
public function testAwaitShouldThrowTheRejectReasonOfRejectedPromiseWithoutNeedingActiveDataLoaderInstance()
840+
{
841+
DataLoader::await(self::$promiseAdapter->createRejected(new \Exception('Rejected!')));
842+
}
843+
812844
public function cacheKey($key)
813845
{
814846
$cacheKey = [];

0 commit comments

Comments
 (0)