Skip to content

Commit 55c1b93

Browse files
committed
perf: run trigger signal effects sync if possible
1 parent ba782d4 commit 55c1b93

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

packages/qwik/src/core/reactive-primitives/impl/wrapped-signal-impl.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
SignalFlags,
1313
WrappedSignalFlags,
1414
} from '../types';
15+
import { triggerEffects } from '../utils';
1516
import { SignalImpl } from './signal-impl';
1617

1718
export class WrappedSignalImpl<T> extends SignalImpl<T> implements BackRef {
@@ -41,12 +42,23 @@ export class WrappedSignalImpl<T> extends SignalImpl<T> implements BackRef {
4142

4243
invalidate() {
4344
this.$flags$ |= SignalFlags.INVALID;
44-
this.$container$?.$scheduler$(
45-
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
46-
this.$hostElement$,
47-
this,
48-
this.$effects$
49-
);
45+
// we are trying to run computation without creating a chore, which can be expensive
46+
// for many signals. If it fails, we schedule a chore to run the computation.
47+
try {
48+
this.$computeIfNeeded$();
49+
} catch (_) {
50+
this.$container$?.$scheduler$(
51+
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
52+
this.$hostElement$,
53+
this,
54+
this.$effects$
55+
);
56+
}
57+
// if the computation not failed, we can run the effects directly
58+
if (this.$flags$ & SignalFlags.RUN_EFFECTS) {
59+
this.$flags$ &= ~SignalFlags.RUN_EFFECTS;
60+
triggerEffects(this.$container$, this, this.$effects$);
61+
}
5062
}
5163

5264
/**
@@ -80,7 +92,14 @@ export class WrappedSignalImpl<T> extends SignalImpl<T> implements BackRef {
8092
this.$container$!
8193
);
8294
// TODO: we should remove invalid flag here, but some tests are failing
95+
// Sometimes we may call .value on wrapped signals without ctx. This means subscription will be
96+
// not created and effects will not be triggered. After wrapping this with if (this.$container$)
97+
// less tests are failing, but still some are failing.
8398
// this.$flags$ &= ~SignalFlags.INVALID;
99+
100+
// reset flag in case we call computedIfNeeded twice and the value was changed only the first time
101+
// TODO: change to version number?
102+
this.$flags$ &= ~SignalFlags.RUN_EFFECTS;
84103
const didChange = untrackedValue !== this.$untrackedValue$;
85104
if (didChange) {
86105
this.$flags$ |= SignalFlags.RUN_EFFECTS;

packages/qwik/src/core/shared/scheduler.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ import { VNodeFlags, type ClientContainer } from '../client/types';
8585
import { VNodeJournalOpCode, vnode_isVNode } from '../client/vnode';
8686
import { vnode_diff } from '../client/vnode-diff';
8787
import { ComputedSignalImpl } from '../reactive-primitives/impl/computed-signal-impl';
88-
import { SignalImpl } from '../reactive-primitives/impl/signal-impl';
89-
import { StoreHandler } from '../reactive-primitives/impl/store';
9088
import { WrappedSignalImpl } from '../reactive-primitives/impl/wrapped-signal-impl';
9189
import { isSignal, type Signal } from '../reactive-primitives/signal.public';
9290
import type { NodePropPayload } from '../reactive-primitives/subscription-data';
@@ -227,7 +225,7 @@ export const createScheduler = (
227225
function schedule(
228226
type: ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
229227
host: HostElement | null,
230-
target: Signal | StoreHandler,
228+
target: Signal<unknown> | StoreTarget,
231229
effects: Set<EffectSubscription> | null
232230
): Chore<ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS>;
233231
function schedule(
@@ -714,11 +712,7 @@ This is often caused by modifying a signal in an already rendered component duri
714712
}
715713
case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
716714
{
717-
const target = chore.$target$ as
718-
| SignalImpl
719-
| ComputedSignalImpl<unknown>
720-
| WrappedSignalImpl<unknown>
721-
| StoreHandler;
715+
const target = chore.$target$ as ComputedSignalImpl<unknown> | WrappedSignalImpl<unknown>;
722716

723717
const effects = chore.$payload$ as Set<EffectSubscription>;
724718
if (!effects?.size) {
@@ -727,6 +721,8 @@ This is often caused by modifying a signal in an already rendered component duri
727721

728722
let shouldCompute =
729723
target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl;
724+
725+
// for .error and .loading effects
730726
if (target instanceof AsyncComputedSignalImpl && effects !== target.$effects$) {
731727
shouldCompute = false;
732728
}

0 commit comments

Comments
 (0)