-
-
Notifications
You must be signed in to change notification settings - Fork 566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to correctly handle multiple deferred / promise? #573
Comments
Have you tried this: 'resolve' => function (Model $model, $_) {
$dataloader = $this->getDataLoaderFor('relation1');
$dataloader->batch($model->relation1_id);
return new Deferred(function () use ($model, $dataloader) {
$relation1 = $dataloader->load($model->relation1_id);
$dataloader2 = $this->getDataLoaderFor('relation2');
$dataloader2->batch($relation1->relation2_id);
return new Deferred(function () use ($relation1, $dataloader2) {
return $dataloader2->load($relation1->relation2_id);
});
});
}, I've added a test for this scenario and it seems to be working as expected. Resolver: graphql-php/tests/Executor/DeferredFieldsTest.php Lines 170 to 187 in 46a99a3
Test: graphql-php/tests/Executor/DeferredFieldsTest.php Lines 556 to 637 in 46a99a3
|
🤔 Well, bummer on my side. I thought I created an example where I would need 3 nested deferrds. But I failed, because I realized as I saw your example, yes, I can correctly reduce it to 2 levels. Ok #fail 😄 But…… I'll try once more to distill my actual question better 🤞 The way I understand it: every dataloader depending on the outcome of another dataloader, needs to be wrapped in a deferred. My initial example has 2 dataloaders, so correctly you nested it twice. So when I've
AKA callback hell. What I tried to come up with, using
I think I can actually do that, with the only restriction:
I.e., same as above but ends with:
Could I better express what I meant? |
Edited. You could try something like this: 'resolve' => function (Model $model, $_) {
$dataloader = $this->getDataLoaderFor('relation1');
$dataloader->batch($model->relation1_id);
$startPromise = new SyncPromise();
$finalPromise = $startPromise
->then(function($model) {
$relation1 = $dataloader->load($model->relation1_id);
$dataloader2 = $this->getDataLoaderFor('relation2');
$dataloader2->batch($relation1->relation2_id);
return $relation1;
})
->then(function($relation1) {
return $dataloader2->load($relation1->relation2_id);
});
return new Deferred(function () use ($model, $startPromise, $finalPromise) {
$startPromise->resolve($model);
return $finalPromise;
});
}, But even if this technique works you should re-check if it actually produces a meaningful sequence of calls to enable batching. I guess we could improve the API to enable Deferreds chaining. I need to think a bit on how to achieve that. |
Can you try PR #581 which should address this? |
In a resolver I need to access:
$model->relation1
=> so I use a dataloaderrelation1
is loaded, I need another relation on that one$relation1->relation2
=> again via dataloaderThere is incentive using the dataloader also for
relation2
because this may be required in other resolvers too (without relation1)I came up with a resolver looking like this:
I know closures are verbose in PHP already 😄 however I realized when I need dependent deferred using
->then()
, I need to wrap it in yet anotherDeferred
because->then()
returns aSyncPromise
which is not handled by webonxy.Is this "amount of code" expected? Is the approach correct / good? Can I simplify the above?
Note: it's not about reducing LoC, I could do that sparing temporary variables. It's more about the approach, because currently it's:
Deferred
->then()
returning aSyncPromise
Deferred
SyncPromise
I need to wrap it in aDeferred
I guess I would have expected I could return
$deferred->then(…)
directly without wrapping it again.Thanks!
The text was updated successfully, but these errors were encountered: