Skip to content

Commit

Permalink
Optimize DataLoader::await method
Browse files Browse the repository at this point in the history
`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.
  • Loading branch information
mcg-web committed Feb 13, 2017
1 parent 0387742 commit 56b0f04
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 12 deletions.
51 changes: 40 additions & 11 deletions src/DataLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,55 @@ protected function getPromiseAdapter()
*/
public static function await($promise = null, $unwrap = true)
{
self::awaitInstances();

if (null === $promise) {
return null;
}

if (is_callable([$promise, 'then'])) {
$isPromiseCompleted = false;
$resolvedValue = null;
$rejectedReason = null;

$promise->then(
function ($value) use (&$isPromiseCompleted, &$resolvedValue) {
$isPromiseCompleted = true;
$resolvedValue = $value;
},
function ($reason) use (&$isPromiseCompleted, &$rejectedReason) {
$isPromiseCompleted = true;
$rejectedReason = $reason;
}
);

//Promise is completed?
if ($isPromiseCompleted) {
// rejected ?
if ($rejectedReason instanceof \Exception) {
if (!$unwrap) {
return $rejectedReason;
}
throw $rejectedReason;
}

return $resolvedValue;
}
}

if (empty(self::$instances)) {
throw new \RuntimeException('Found no active DataLoader instance.');
}
self::awaitInstances();

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

private static function awaitInstances()
{
$dataLoaders = self::$instances;
do {
$wait = false;
$dataLoaders = self::$instances;

$wait = true;

while ($wait) {
foreach ($dataLoaders as $dataLoader) {
if (!$dataLoader || !$dataLoader->needProcess()) {
$wait = false;
Expand All @@ -262,12 +296,7 @@ private static function awaitInstances()
$wait = true;
$dataLoader->process();
}
}

// If new dataloaders were instanciated in the meantime, wait again !
if (count($dataLoaders) != count(self::$instances)) {
self::awaitInstances();
}
} while ($wait);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/AbuseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function testAwaitPromiseMustHaveAThenMethod()
*/
public function testAwaitWithoutNoInstance()
{
DataLoader::await();
DataLoader::await(self::$promiseAdapter->create());
}

/**
Expand Down
32 changes: 32 additions & 0 deletions tests/DataLoadTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,38 @@ public function testAwaitAlsoAwaitsNewlyCreatedDataloaders()
$this->assertTrue($secondComplete);
}

/**
* @runInSeparateProcess
*/
public function testAwaitShouldReturnTheValueOfFulfilledPromiseWithoutNeedingActiveDataLoaderInstance()
{
$expectedValue = 'Ok!';
$value = DataLoader::await(self::$promiseAdapter->createFulfilled($expectedValue));

$this->assertEquals($expectedValue, $value);
}

/**
* @runInSeparateProcess
*/
public function testAwaitShouldReturnTheRejectReasonOfRejectedPromiseWithoutNeedingActiveDataLoaderInstance()
{
$expectedException = new \Exception('Rejected!');
$exception = DataLoader::await(self::$promiseAdapter->createRejected($expectedException), false);

$this->assertEquals($expectedException, $exception);
}

/**
* @expectedException \Exception
* @expectedExceptionMessage Rejected!
* @runInSeparateProcess
*/
public function testAwaitShouldThrowTheRejectReasonOfRejectedPromiseWithoutNeedingActiveDataLoaderInstance()
{
DataLoader::await(self::$promiseAdapter->createRejected(new \Exception('Rejected!')));
}

public function cacheKey($key)
{
$cacheKey = [];
Expand Down

0 comments on commit 56b0f04

Please sign in to comment.