Skip to content

Commit 73f99b3

Browse files
committed
fix: diffing async computed and promise inside signal
1 parent ba9a485 commit 73f99b3

File tree

2 files changed

+37
-40
lines changed

2 files changed

+37
-40
lines changed

packages/qwik/src/core/client/vnode-diff.ts

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { JSXNodeImpl, isJSXNode } from '../shared/jsx/jsx-node';
1414
import { Fragment, type Props } from '../shared/jsx/jsx-runtime';
1515
import { directGetPropsProxyProp, type PropsProxy } from '../shared/jsx/props-proxy';
1616
import { Slot } from '../shared/jsx/slot.public';
17-
import type { JSXNodeInternal, JSXOutput } from '../shared/jsx/types/jsx-node';
17+
import type { JSXNodeInternal } from '../shared/jsx/types/jsx-node';
1818
import type { JSXChildren } from '../shared/jsx/types/jsx-qwik-attributes';
1919
import { SSRComment, SSRRaw, SkipRender } from '../shared/jsx/utils.public';
2020
import type { QRLInternal } from '../shared/qrl/qrl-class';
@@ -85,7 +85,7 @@ import { getAttributeNamespace, getNewElementNamespaceData } from './vnode-names
8585

8686
export const vnode_diff = (
8787
container: ClientContainer,
88-
jsxNode: JSXOutput,
88+
jsxNode: JSXChildren,
8989
vStartNode: VNode,
9090
scopedStyleIdPrefix: string | null
9191
) => {
@@ -99,8 +99,7 @@ export const vnode_diff = (
9999
*/
100100
const stack: any[] = [];
101101

102-
const asyncQueue: Array<VNode | ValueOrPromise<JSXOutput> | Promise<JSXOutput | JSXChildren>> =
103-
[];
102+
const asyncQueue: Array<VNode | ValueOrPromise<JSXChildren> | Promise<JSXChildren>> = [];
104103

105104
////////////////////////////////
106105
//// Traverse state variables
@@ -152,7 +151,7 @@ export const vnode_diff = (
152151
//////////////////////////////////////////////
153152
//////////////////////////////////////////////
154153

155-
function diff(jsxNode: JSXOutput, vStartNode: VNode) {
154+
function diff(jsxNode: JSXChildren, vStartNode: VNode) {
156155
assertFalse(vnode_isVNode(jsxNode), 'JSXNode should not be a VNode');
157156
assertTrue(vnode_isVNode(vStartNode), 'vStartNode should be a VNode');
158157
vParent = vStartNode as ElementVNode | VirtualVNode;
@@ -185,15 +184,8 @@ export const vnode_diff = (
185184
if (currentSignal !== unwrappedSignal) {
186185
const vHost = (vNewNode || vCurrent)!;
187186
descend(
188-
resolveSignalAndDescend(
189-
retryOnPromise(() =>
190-
trackSignalAndAssignHost(
191-
unwrappedSignal,
192-
vHost,
193-
EffectProperty.VNODE,
194-
container
195-
)
196-
)
187+
resolveSignalAndDescend(() =>
188+
trackSignalAndAssignHost(unwrappedSignal, vHost, EffectProperty.VNODE, container)
197189
),
198190
true
199191
);
@@ -252,12 +244,19 @@ export const vnode_diff = (
252244
}
253245
}
254246

255-
function resolveSignalAndDescend(value: any) {
256-
if (isPromise(value)) {
257-
asyncQueue.push(value, vNewNode || vCurrent, null);
258-
return null;
247+
function resolveSignalAndDescend(fn: () => ValueOrPromise<any>): ValueOrPromise<any> {
248+
try {
249+
return fn();
250+
} catch (e) {
251+
// Signal threw a promise (async computed signal) - handle retry and async queue
252+
if (isPromise(e)) {
253+
// The thrown promise will resolve when the signal is ready, then retry fn() with retry logic
254+
const retryPromise = e.then(() => retryOnPromise(fn));
255+
asyncQueue.push(retryPromise, vNewNode || vCurrent, null);
256+
return null;
257+
}
258+
throw e;
259259
}
260-
return value;
261260
}
262261

263262
function advance() {
@@ -544,29 +543,30 @@ export const vnode_diff = (
544543

545544
function drainAsyncQueue(): ValueOrPromise<void> {
546545
while (asyncQueue.length) {
547-
const jsxNode = asyncQueue.shift() as ValueOrPromise<JSXNodeInternal>;
546+
let jsxNode = asyncQueue.shift() as ValueOrPromise<JSXChildren>;
548547
const vHostNode = asyncQueue.shift() as VNode;
549548
const styleScopedId = asyncQueue.shift() as string | null;
549+
550+
const diffNode = (jsxNode: JSXChildren, vHostNode: VNode, styleScopedId: string | null) => {
551+
if (styleScopedId) {
552+
vnode_diff(container, jsxNode, vHostNode, addComponentStylePrefix(styleScopedId));
553+
} else {
554+
diff(jsxNode, vHostNode);
555+
}
556+
};
557+
550558
if (isPromise(jsxNode)) {
551559
return jsxNode
552560
.then((jsxNode) => {
553-
if (styleScopedId) {
554-
vnode_diff(container, jsxNode, vHostNode, addComponentStylePrefix(styleScopedId));
555-
} else {
556-
diff(jsxNode, vHostNode);
557-
}
561+
diffNode(jsxNode, vHostNode, styleScopedId);
558562
return drainAsyncQueue();
559563
})
560564
.catch((e) => {
561565
container.handleError(e, vHostNode);
562566
return drainAsyncQueue();
563567
});
564568
} else {
565-
if (styleScopedId) {
566-
vnode_diff(container, jsxNode, vHostNode, addComponentStylePrefix(styleScopedId));
567-
} else {
568-
diff(jsxNode, vHostNode);
569-
}
569+
diffNode(jsxNode, vHostNode, styleScopedId);
570570
}
571571
}
572572
}
@@ -1280,15 +1280,7 @@ export const vnode_diff = (
12801280
* deleted.
12811281
*/
12821282
(host as VirtualVNode).flags &= ~VNodeFlags.Deleted;
1283-
// container.$scheduler$(ChoreType.COMPONENT, host, componentQRL, vNodeProps);
1284-
1285-
try {
1286-
const jsxOutput = executeComponent(container, host, host, componentQRL, vNodeProps);
1287-
const styleScopedId = container.getHostProp<string>(host, QScopedStyle);
1288-
asyncQueue.push(jsxOutput, host, styleScopedId);
1289-
} catch (e) {
1290-
container.handleError(e, host);
1291-
}
1283+
container.$scheduler$(ChoreType.COMPONENT, host, componentQRL, vNodeProps);
12921284
}
12931285
}
12941286
descendContentToProject(jsxChildren, host);

packages/qwik/src/core/tests/use-task.spec.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
Fragment as Component,
33
Fragment,
44
Fragment as Signal,
5+
Fragment as Awaited,
56
Slot,
67
component$,
78
isServer,
@@ -598,7 +599,11 @@ describe.each([
598599
expect(vNode).toMatchVDOM(
599600
<Component>
600601
<p>
601-
Should have a number: "<Fragment>3</Fragment>"
602+
Should have a number: "
603+
<Signal>
604+
<Awaited>3</Awaited>
605+
</Signal>
606+
"
602607
</p>
603608
</Component>
604609
);

0 commit comments

Comments
 (0)