今までの 2 回ともおもしろかったので、またやってみました。
wings.hatenablog.com
wings.hatenablog.com
今回の計測は、「そんなことしない集」です。
- ネストされた最深部のコンポーネントから最上部への伝播時間
- Effect や Memo 系での 10 連鎖の伝播時間
- 並列に読み込んだコンポーネントの Context / Store での 50 連鎖の伝播時間
1 つめの最深部からの伝播は、単純に Svelte の $bindable() での伝播がどれくらいなのかを見たかったのです。共通の対象は Context / Store(Qwik 以外)/ Setter のバケツリレーです。
2 つめの 10 連鎖は、Effect や Memo で差が出るのか測ってみたかったです。フレームワークにより useLayoutEffect や watchEffect なども対象に入れました。
3 つめの 50 連鎖は、これも単純に、どちらが速いのか気になったんです。Context / Store 共に計測開始のコンポーネントと島を分けたので、開始の伝播のみどちらも Store を用いました。コンポーネントは 10 個用意し、5 回ループで 50 連鎖としました。本当は 1000 連鎖にしたかったんですが、Svelte の連鎖制限に引っかかって 100 連鎖になり、React の連鎖制限に引っかかって 50 連鎖になりました。普通はこんなに連鎖させないのですけどね...。
なお、今回は、前回までの計測結果上、最も速かったテンプレート無しのみの計測としました(React も Memo 無し)。
Solid / Svelte / Vue のグローバルストアについての詳細は、こちらを参照してください。
wings.hatenablog.com
では、早速いきましょう。今回も import 文は割愛します。また、他の割愛部分は、都度記載します。
共通
計測方法は前回と同じです。
export const records = {
RelaySetter: {
start: 0,
finished: 0,
},
RelayContext: {
start: 0,
finished: 0,
},
RelayStore: {
start: 0,
finished: 0,
},
RelayBindable: {
start: 0,
finished: 0,
},
RaceDerivedState: {
start: 0,
finished: 0,
},
RaceWatchState: {
start: 0,
finished: 0,
},
RaceComputedState: {
start: 0,
finished: 0,
},
RaceWatchEffectState: {
start: 0,
finished: 0,
},
RaceEffectState: {
start: 0,
finished: 0,
},
RaceMemoState: {
start: 0,
finished: 0,
},
RaceLayoutEffectState: {
start: 0,
finished: 0,
},
QuantumContext: {
start: 0,
finished: 0,
},
QuantumStore: {
start: 0,
finished: 0,
},
};
export type Records = keyof typeof records;
const now = () => performance.now();
export const recordStart = (target: Records) => {
records[target].start = now();
};
export const recordFinished = (target: Records, name?: string) => {
if (records[target].start === 0) return;
records[target].finished = now();
const diff = records[target].finished - records[target].start;
console.log(`${name ?? target}: ${diff} ミリ秒`);
};
export const loopTotal = 5;
以下は Solid 版で、Svelte / Vue / React 共に同じ構成ですが、上述の useLayoutEffect や watchEffect などの追加がある場合はコンポーネントが増えます。
なお、最深部以外は開始ボタンを持つコンポーネントのみ client:load とし、実際の計測は client:only としてレンダリングを極力巻き込まないようにしたつもりです。
Parent は最深部からの伝播計測、Circuit / RaceEffect / RaceMemo は 10 連鎖計測、QuantumStart は 50 連鎖の開始、QuantumCircuit は 50 連鎖の Context 用、Quantum00〜Quantum10 は 50 連鎖の Store 用です。
<div id="performance">
<Parent client:load />
<Circuit client:load />
<RaceEffect client:only="solid" />
<RaceMemo client:only="solid" />
<QuantumStart client:load />
<QuantumCircuit client:only="solid" />
<Quantum00 client:only="solid" />
</div>
CSS
前回と同様にこれだけです。
#performance {
width: 750px;
margin: 0 auto;
}
型定義
最深部からの伝播用にまとめます。
export type RelayData = number;
export type RelaySetter = (_: RelayData) => void;
export type RelayProps = {
relay: RelayData;
setRelay: RelaySetter;
};
Solid 版
最深部からの伝播用グローバルストア設定
前回のバケツリレーと全く同じです。
type Relay = number;
const initialValue: Relay = 0;
export const _solidRelay = {
server: {
solidRelay: (): Relay => initialValue,
solidSetRelay: (_: Relay) => {},
},
client: () => {
const [ solidRelay, solidSetRelay ] = createSignal<Relay>(initialValue);
return { solidRelay, solidSetRelay };
},
};
最深部からの伝播用 Context 設定
こちらも前回のバケツリレーと全く同じです。
export type RelayData = number;
export type RelayProps = {
relay: RelayData;
};
const createRelayDataContexts = () => {
const [ relayData, setRelayData ] = createSignal<RelayData>(0);
return { relayData, setRelayData };
};
type RelayDataContextsType = ReturnType<typeof createRelayDataContexts>;
const RelayDataContexts = createContext<RelayDataContextsType>() as Context<RelayDataContextsType>;
export const RelayDataProvider = (props: { children: JSX.Element }) => {
return (
RelayDataContexts.Provider value={ createRelayDataContexts() }{ props.children }RelayDataContexts.Provider
);
}
export const useRelayDataContexts = () => useContext(RelayDataContexts);
Parent.tsx
Context で包む親コンポーネントです。
export default function Parent() {
return (
RelayDataProvider
Child00
RelayDataProvider
)
};
Child00.tsx
最深部からのゴール地点であるコンポーネントです。
export default function Child00() {
const { relayData } = useRelayDataContexts();
const { solidRelay } = useStore('solidRelay');
const [ relay, setRelay ] = createSignal<RelayData>(0);
createEffect(() => {
if (!relay()) return;
recordFinished('RelaySetter');
});
createEffect(() => {
if (!relayData()) return;
recordFinished('RelayContext');
});
createEffect(() => {
if (!solidRelay()) return;
recordFinished('RelayStore');
});
return Child01 relay={ relay() } setRelay={ setRelay } ;
}
Child01.tsx
中継地点となる子コンポーネントです(Child09.tsx まで割愛します)
export default function Child01(props: RelayProps) {
return Child02 relay={ props.relay } setRelay={ props.setRelay } ;
};
Child10.tsx
計測を開始する最深部のコンポーネントです。
export default function Child10(props: RelayProps) {
const { relayData, setRelayData } = useRelayDataContexts();
const { solidSetRelay } = useStore('solidRelay');
const handleChange = () => {
const start = relayData() + 1;
recordStart('RelaySetter');
props.setRelay(start);
recordStart('RelayContext');
setRelayData(start);
recordStart('RelayStore');
solidSetRelay(start);
};
return (
fieldset
input type="number" value={ props.relay } onChange={ handleChange }
fieldset
)
};
10 連鎖用グローバルストア設定
type RaceNo = number;
const initialValue: RaceNo = 0;
export const _solidRaceNo = {
server: {
solidRaceNo: (): RaceNo => initialValue,
solidSetRaceNo: (_: RaceNo) => {},
},
client: () => {
const [ solidRaceNo, solidSetRaceNo ] = createSignal<RaceNo>(initialValue);
return { solidRaceNo, solidSetRaceNo };
},
};
Circuit.tsx
10 連鎖の計測開始コンポーネントです。
export default function Circuit() {
const { solidRaceNo, solidSetRaceNo } = useStore('solidRaceNo');
const handleClick = () => {
solidSetRaceNo(solidRaceNo() + 1);
};
return (
fieldset
button onClick={ handleClick }10 連鎖スタートbutton
fieldset
)
}
RaceEffect.tsx
createEffect() で繋いでいくコンポーネントです。
export default function RaceEffect() {
const { solidRaceNo } = useStore('solidRaceNo');
const [ state01, setState01 ] = createSignal(0);
createEffect(() => {
if (!solidRaceNo()) return;
recordStart('RaceEffectState');
setState01(solidRaceNo() + 1);
});
createEffect(() => {
if (!state01()) return;
setState02(state01());
});
createEffect(() => {
if (!state10()) return;
recordFinished('RaceEffectState');
});
return null;
}
RaceMemo.tsx
createMemo() で繋いでいくコンポーネントです。
export default function RaceMemo() {
const { solidRaceNo } = useStore('solidRaceNo')
const state01 = createMemo(() => {
if (!solidRaceNo()) return 0;
recordStart('RaceMemoState');
return solidRaceNo() + 1;
});
const state02 = createMemo(() => {
if (!state01()) return;
return state01();
});
createMemo(() => {
if (!state10()) return;
recordFinished('RaceMemoState');
});
return null;
}
50 連鎖用グローバルストア設定
type Quantum = number;
const initialValue: Quantum = 0;
export const _solidQuantum = {
server: {
solidQuantumContextStart: (): Quantum => initialValue,
solidSetQuantumContextStart: (_: Quantum) => {},
solidQuantumStoreStart: (): Quantum => initialValue,
solidSetQuantumStoreStart: (_: Quantum) => {},
solidQuantum01: (): Quantum => initialValue,
solidSetQuantum01: (_: Quantum) => {},
},
client: () => {
const [ solidQuantumContextStart, solidSetQuantumContextStart ] = createSignal<Quantum>(initialValue);
const [ solidQuantumStoreStart, solidSetQuantumStoreStart ] = createSignal<Quantum>(initialValue);
const [ solidQuantum01, solidSetQuantum01 ] = createSignal<Quantum>(initialValue);
return {
solidQuantumContextStart, solidSetQuantumContextStart,
solidQuantumStoreStart, solidSetQuantumStoreStart,
solidQuantum01, solidSetQuantum01,
};
},
};
50 連鎖用 Context 設定
export type QuantumData = number;
const createQuantumDataContexts = () => {
const [ quantumData01, setQuantumData01 ] = createSignal<QuantumData>(0);
return {
quantumData01, setQuantumData01,
};
};
type QuantumDataContextsType = ReturnType<typeof createQuantumDataContexts>;
const QuantumDataContexts = createContext<QuantumDataContextsType>() as Context<QuantumDataContextsType>;
export const QuantumDataProvider = (props: { children: JSX.Element }) => {
return (
QuantumDataContexts.Provider value={ createQuantumDataContexts() }{ props.children }QuantumDataContexts.Provider
);
}
export const useQuantumDataContexts = () => useContext(QuantumDataContexts);
QuantumStart.tsx
50 連鎖の計測開始用コンポーネントです。
export default function QuantumStart() {
const { solidSetQuantumContextStart, solidSetQuantumStoreStart } = useStore('solidQuantum');
const handleClick = () => {
solidSetQuantumContextStart(1);
solidSetQuantumStoreStart(1);
};
return (
fieldset
button onClick={ handleClick }50 連鎖スタートbutton
fieldset
)
}
QuantumCircuit.tsx
50 連鎖の Context 包み用コンポーネントです。
export default function QuantumCircuit() {
return (
QuantumDataProvider
Quantum00
// 10 まで同じ構造が続きます
QuantumDataProvider
)
}
_quantumContexts/Quantum00.tsx
計測開始を受け取り、50 連鎖の Context コンポーネントへ流し始めるコンポーネントです。
export default function Quantum00() {
const { solidQuantumContextStart } = useStore('solidQuantum');
const { setQuantumData01 } = useQuantumDataContexts();
createEffect(() => {
if (!solidQuantumContextStart()) return;
recordStart('QuantumContext');
setQuantumData01(solidQuantumContextStart());
});
return null;
}
_quantumContexts/Quantum01.tsx
中継地点のコンポーネントです(Quantum09.tsx まで省きます)
export default function Quantum01() {
const { quantumData01, setQuantumData02 } = useQuantumDataContexts();
createEffect(() => {
if (!quantumData01()) return;
setQuantumData02(quantumData01());
});
return null;
}
_quantumContexts/Quantum10.tsx
Context 50 連鎖を計測するコンポーネントです。
export default function Quantum10() {
const { solidSetQuantumContextStart } = useStore('solidQuantum');
const { setQuantumData01, quantumData10 } = useQuantumDataContexts();
const incrementContext = (value: number) => {
setQuantumData01(value + 1);
};
createEffect(() => {
if (!quantumData10()) return;
if (quantumData10() >= loopTotal) {
recordFinished('QuantumContext');
solidSetQuantumContextStart(0);
return;
}
incrementContext(quantumData10());
});
return null;
}
_quantumStores/Quantum00.tsx
計測開始を受け取り、50 連鎖の Store コンポーネントへ流し始めるコンポーネントです。
export default function Quantum00() {
const { solidQuantumStoreStart, solidSetQuantum01 } = useStore('solidQuantum');
createEffect(() => {
if (!solidQuantumStoreStart()) return;
recordStart('QuantumStore');
solidSetQuantum01(solidQuantumStoreStart());
});
return null;
}
_quantumStores/Quantum01.tsx
中継地点のコンポーネントです(Quantum09.tsx まで省きます)
export default function Quantum01() {
const { solidQuantum01, solidSetQuantum02 } = useStore('solidQuantum');
createEffect(() => {
if (!solidQuantum01()) return;
solidSetQuantum02(solidQuantum01());
});
return null;
}
_quantumStores/Quantum10.tsx
Store 50 連鎖を計測するコンポーネントです。
export default function Quantum10() {
const { solidSetQuantumStoreStart, solidSetQuantum01, solidQuantum10 } = useStore('solidQuantum');
const incrementStore = (value: number) => {
solidSetQuantum01(value + 1);
};
createEffect(() => {
if (!solidQuantum10()) return;
if (solidQuantum10() >= loopTotal) {
recordFinished('QuantumStore');
solidSetQuantumStoreStart(0);
return;
}
incrementStore(solidQuantum10());
});
return null;
}
Svelte 版
最深部からの伝播用グローバルストア設定
type Relay = number;
const initialValue: Relay = 0;
export const _svelteRelay = {
server: {
svelteRelay: (): Relay => initialValue,
svelteSetRelay: (_: Relay) => {},
},
client: () => {
let svelteRelay = $state<Relay>(initialValue);
const svelteSetRelay = (value: Relay) => { svelteRelay = value; };
return { svelteRelay: () => svelteRelay, svelteSetRelay };
},
};
最深部からの伝播用 Context 設定
const createRelayDataContexts = () => {
const states = $state({
relayData: 0,
});
type States = typeof states;
return {
relayData: () => states.relayData,
setRelayData: (value: States['relayData'] = 0) => states.relayData = value,
};
};
const [ useRelayDataContexts, setRelayDataContexts ] = createContext<ReturnType<typeof createRelayDataContexts>>();
export type RelayProps = {
relay: ReturnType<ReturnType<typeof createRelayDataContexts>['relayData']>;
}
export const provideRelayDataContexts = () => setRelayDataContexts(createRelayDataContexts());
export { useRelayDataContexts };
Parent.svelte
<script lang="ts">
provideRelayDataContexts();
</script>
<Child00 />
Child00.svelte
<script lang="ts">
const { relayData } = useRelayDataContexts();
const { svelteRelay } = useStore('svelteRelay');
let val = $state(0);
let relay = $state(0);
const setRelay: RelaySetter = (value: RelayData) => { relay = value; };
$effect(() => {
if (!relay) return;
recordFinished('RelaySetter');
});
$effect(() => {
if (!relayData()) return;
recordFinished('RelayContext');
});
$effect(() => {
if (!svelteRelay()) return;
recordFinished('RelayStore');
});
$effect(() => {
if (!val) return;
recordFinished('RelayBindable');
});
</script>
<Child01 bind:relay={ val } setRelay={ setRelay } />
Child01.svelte
<script lang="ts">
let { relay = $bindable(), setRelay }: RelayProps = $props();
</script>
<Child02 bind:relay={ relay } setRelay={ setRelay } />
Child10.svelte
<script lang="ts">
let { relay = $bindable(), setRelay }: RelayProps = $props();
const { relayData, setRelayData } = useRelayDataContexts();
const { svelteSetRelay } = useStore('svelteRelay');
const handleChange = () => {
const start = relayData() + 1;
recordStart('RelaySetter');
setRelay(start);
recordStart('RelayContext');
setRelayData(start);
recordStart('RelayStore');
svelteSetRelay(start);
};
$effect(() => {
if (!relay) return;
recordStart('RelayBindable');
});
</script>
<fieldset>
<input type="number" onchange={ handleChange } bind:value={ relay }>
</fieldset>
10 連鎖用グローバルストア設定
type RaceNo = number;
const initialValue: RaceNo = 0;
export const _svelteRaceNo = {
server: {
svelteRaceNo: (): RaceNo => initialValue,
svelteSetRaceNo: (_: RaceNo) => {},
},
client: () => {
let svelteRaceNo = $state<RaceNo>(initialValue);
const svelteSetRaceNo = (value: RaceNo) => { svelteRaceNo = value; };
return { svelteRaceNo: () => svelteRaceNo, svelteSetRaceNo };
},
};
Circuit.svelte
<script lang="ts">
const { svelteRaceNo, svelteSetRaceNo } = useStore('svelteRaceNo');
const handleClick = () => {
svelteSetRaceNo(svelteRaceNo() + 1);
};
</script>
<fieldset>
<button onclick={ handleClick }>10 連鎖スタート</button>
</fieldset>
RaceEffect.svelte
$effect() で繋いでいくコンポーネントです。
<script lang="ts">
import { recordStart, recordFinished } from "@/_global/lib/performance03";
import { useStore } from "@/_global/piquo";
const { svelteRaceNo } = useStore('svelteRaceNo');
let state01 = $state(0);
const setState01 = (value: number) => { state01 = value; };
$effect(() => {
if (!svelteRaceNo()) return;
recordStart('RaceEffectState');
setState01(svelteRaceNo() + 1);
});
$effect(() => {
if (!state01) return;
setState02(state01);
});
$effect(() => {
if (!state10) return;
recordFinished('RaceEffectState');
});
</script>
RaceDerived.svelte
$derived.by() で繋いでいくコンポーネントです。finished を最終的に使わなければ計算しないため、致し方なくさらに $derived.by() を追加して監視だけしています。
<script lang="ts">
const { svelteRaceNo } = useStore('svelteRaceNo');
const state01 = $derived.by(() => {
if (!svelteRaceNo()) return;
recordStart('RaceDerivedState');
return svelteRaceNo() + 1;
});
const state02 = $derived.by(() => {
if (!state01) return;
return state01;
});
const finished = $derived.by(() => {
recordFinished('RaceDerivedState');
return state10;
});
$effect.pre(() => { const _ = finished });
</script>
50 連鎖用グローバルストア設定
type Quantum = number;
const initialValue: Quantum = 0;
export const _svelteQuantum = {
server: {
svelteQuantumContextStart: (): Quantum => initialValue,
svelteSetQuantumContextStart: (_: Quantum) => {},
svelteQuantumStoreStart: (): Quantum => initialValue,
svelteSetQuantumStoreStart: (_: Quantum) => {},
svelteQuantum01: (): Quantum => initialValue,
svelteSetQuantum01: (_: Quantum) => {},
},
client: () => {
let svelteQuantumContextStart = $state<Quantum>(initialValue);
const svelteSetQuantumContextStart = (value: Quantum) => { svelteQuantumContextStart = value; };
let svelteQuantumStoreStart = $state<Quantum>(initialValue);
const svelteSetQuantumStoreStart = (value: Quantum) => { svelteQuantumStoreStart = value; };
let svelteQuantum01 = $state<Quantum>(initialValue);
const svelteSetQuantum01 = (value: Quantum) => { svelteQuantum01 = value; };
return {
svelteQuantumContextStart: () => svelteQuantumContextStart, svelteSetQuantumContextStart,
svelteQuantumStoreStart: () => svelteQuantumStoreStart, svelteSetQuantumStoreStart,
svelteQuantum01: () => svelteQuantum01, svelteSetQuantum01,
};
},
};
50 連鎖用 Context svelte
const createQuantumDataContexts = () => {
const states = $state({
quantumData01: 0,
});
type States = typeof states;
return {
quantumData01: () => states.quantumData01,
setQuantumData01: (value: States['quantumData01'] = 0) => states.quantumData01 = value,
};
};
const [ useQuantumDataContexts, setQuantumDataContexts ] = createContext<ReturnType<typeof createQuantumDataContexts>>();
export const provideQuantumDataContexts = () => setQuantumDataContexts(createQuantumDataContexts());
export { useQuantumDataContexts };
QuantumStart.svelte
<script lang="ts">
const { svelteSetQuantumStoreStart, svelteSetQuantumContextStart } = useStore('svelteQuantum');
const handleClick = () => {
svelteSetQuantumContextStart(1);
svelteSetQuantumStoreStart(1);
};
</script>
<fieldset>
<button onclick={ handleClick }>50 連鎖スタート</button>
</fieldset>
QuantumCircuit.svelte
<script lang="ts">
provideQuantumDataContexts();
</script>
<Quantum00 />
_quantumContexts/Quantum00.svelte
<script lang="ts">
const { svelteQuantumContextStart } = useStore('svelteQuantum');
const { setQuantumData01 } = useQuantumDataContexts();
$effect(() => {
if (!svelteQuantumContextStart()) return;
recordStart('QuantumContext');
setQuantumData01(svelteQuantumContextStart());
});
</script>
_quantumContexts/Quantum01.svelte
<script lang="ts">
const { quantumData01, setQuantumData02 } = useQuantumDataContexts();
$effect(() => {
if (!quantumData01()) return;
setQuantumData02(quantumData01());
});
</script>
_quantumContexts/Quantum10.svelte
<script lang="ts">
const { svelteSetQuantumContextStart } = useStore('svelteQuantum');
const { setQuantumData01, quantumData10 } = useQuantumDataContexts();
const incrementContext = (value: number) => {
setQuantumData01(value + 1);
};
$effect(() => {
if (!quantumData10()) return;
if (quantumData10() >= loopTotal) {
recordFinished('QuantumContext');
svelteSetQuantumContextStart(0);
return;
}
incrementContext(quantumData10());
});
</script>
_quantumStores/Quantum00.svelte
<script lang="ts">
const { svelteQuantumStoreStart, svelteSetQuantum01 } = useStore('svelteQuantum');
$effect(() => {
if (!svelteQuantumStoreStart()) return;
recordStart('QuantumStore');
svelteSetQuantum01(svelteQuantumStoreStart());
});
</script>
_quantumStores/Quantum01.svelte
<script lang="ts">
const { svelteQuantum01, svelteSetQuantum02 } = useStore('svelteQuantum');
$effect(() => {
if (!svelteQuantum01()) return;
svelteSetQuantum02(svelteQuantum01());
});
</script>
_quantumStores/Quantum10.svelte
<script lang="ts">
const { svelteSetQuantumStoreStart, svelteSetQuantum01, svelteQuantum10 } = useStore('svelteQuantum');
const incrementStore = (value: number) => {
svelteSetQuantum01(value + 1);
};
$effect(() => {
if (!svelteQuantum10()) return;
if (svelteQuantum10() >= loopTotal) {
recordFinished('QuantumStore');
svelteSetQuantumStoreStart(0);
return;
}
incrementStore(svelteQuantum10());
});
</script>
Vue 版
最深部からの伝播用グローバルストア設定
type Relay = number;
const initialValue: Relay = 0;
export const _vueRelay = {
server: {
vueRelay: (): Relay => initialValue,
vueSetRelay: (_: Relay) => {},
},
client: () => {
const vueRelay = ref<Relay>(initialValue);
const vueSetRelay = (value: Relay) => { vueRelay.value = value; };
return { vueRelay: () => vueRelay.value, vueSetRelay };
},
};
最深部からの伝播用 Context 設定
<script lang="ts">
type RelayData = number;
const initialValue: RelayData = 0;
type RelayDataRef = Ref<RelayData>;
const RelayDataSymbol: InjectionKey<RelayDataRef> = Symbol();
const provideRelayData = (value: RelayDataRef) => {
provide(RelayDataSymbol, value);
};
export const useRelayDataContexts = () => {
const injected = inject(RelayDataSymbol);
if (!injected) {
return {
relayData: readonly({ value: initialValue }),
setRelayData: (_: RelayData) => {},
}
};
const relayData = readonly(injected);
const setRelayData = (value: RelayData) => { injected.value = value; };
return { relayData, setRelayData };
};
export type RelayProps = {
relay: ReturnType<typeof useRelayDataContexts>['relayData'];
};
export default defineComponent({
name: 'Relay',
props: {
relay: {
type: Number as PropType<RelayData>,
default: initialValue,
},
},
setup(props) {
provideRelayData(ref(props.relay));
}
});
</script>
<template>
<slot />
</template>
Parent.vue
<template>
<RelayContext>
<Child00 />
</RelayContext>
</template>
Child00.vue
<script setup lang="ts">
const { relayData } = useRelayDataContexts();
const { vueRelay } = useStore('vueRelay');
let relay = ref(0);
const setRelay: RelaySetter = (value: RelayData) => { relay.value = value; };
watch(
() => relay.value,
() => {
if (!relay.value) return;
recordFinished('RelaySetter');
},
{ immediate: true }
);
watch(
() => relayData.value,
() => {
if (!relayData.value) return;
recordFinished('RelayContext');
},
{ immediate: true }
);
watch(
() => vueRelay(),
() => {
if (!vueRelay()) return;
recordFinished('RelayStore');
},
{ immediate: true }
);
</script>
<template>
<Child01 :relay="relay" :set-relay="setRelay" />
</template>
Child01.vue
<script setup lang="ts">
const props = defineProps<RelayProps>();
</script>
<template>
<Child02 :relay="props.relay" :set-relay="props.setRelay" />
</template>
Child10.vue
<script setup lang="ts">
const props = defineProps<RelayProps>();
const { relayData, setRelayData } = useRelayDataContexts();
const { vueSetRelay } = useStore('vueRelay');
const handleChange = async () => {
const start = relayData.value + 1;
recordStart('RelaySetter');
props.setRelay(start);
recordStart('RelayContext');
setRelayData(start);
recordStart('RelayStore');
vueSetRelay(start);
};
</script>
<template>
<fieldset>
<input type="number" @change="handleChange" :value="props.relay">
</fieldset>
</template>
10 連鎖用グローバルストア設定
type RaceNo = number;
const initialValue: RaceNo = 0;
export const _vueRaceNo = {
server: {
vueRaceNo: (): RaceNo => initialValue,
vueSetRaceNo: (_: RaceNo) => {},
},
client: () => {
const vueRaceNo = ref<RaceNo>(initialValue);
const vueSetRaceNo = (value: RaceNo) => { vueRaceNo.value = value; };
return { vueRaceNo: () => vueRaceNo.value, vueSetRaceNo };
},
};
Circuit.vue
<script setup lang="ts">
const { vueRaceNo, vueSetRaceNo } = useStore('vueRaceNo');
const handleClick = () => {
vueSetRaceNo(vueRaceNo() + 1);
};
</script>
<template>
<fieldset>
<button @click="handleClick">10 連鎖スタート</button>
</fieldset>
</template>
RaceWatch.vue
watch() で繋いでいくコンポーネントです。
<script setup lang="ts">
const { vueRaceNo } = useStore('vueRaceNo');
const state01 = ref(0);
watch(
() => vueRaceNo(),
() => {
if (!vueRaceNo()) return;
recordStart('RaceWatchState');
state01.value++;
},
{ immediate: true }
);
watch(
() => state01.value,
() => {
if (!state01.value) return;
state02.value++;
},
{ immediate: true }
);
watch(
() => state10.value,
() => {
if (!state10.value) return;
recordFinished('RaceWatchState');
},
{ immediate: true }
);
</script>
<template>
</template>
RaceComputed.vue
computed() で繋いでいくコンポーネントです。finished を最終的に使わなければ計算しないため、致し方なく空の watch() で監視だけしています。
<script setup lang="ts">
const { vueRaceNo } = useStore('vueRaceNo');
const state01 = computed(() => {
if (!vueRaceNo()) return;
recordStart('RaceComputedState');
return vueRaceNo() + 1;
});
const state02 = computed(() => {
if (!state01.value) return;
return state01.value;
});
const finished = computed(() => {
if (!state10.value) return;
recordFinished('RaceComputedState');
return state10.value;
});
watch(() => finished.value, () => {});
</script>
<template>
</template>
RaceWatchEffect.vue
watchEffect() で繋いでいくコンポーネントです。
<script setup lang="ts">
const { vueRaceNo } = useStore('vueRaceNo');
const state01 = ref(0);
const setState01 = (value: number) => { state01.value = value; };
watchEffect(
() => {
if (!vueRaceNo()) return;
recordStart('RaceWatchEffectState');
setState01(vueRaceNo() + 1);
}, { flush: 'pre' }
);
watchEffect(
() => {
if (!state01.value) return;
setState02(state01.value);
}, { flush: 'pre' }
);
watchEffect(
() => {
if (!state10.value) return;
recordFinished('RaceWatchEffectState');
}, { flush: 'pre' }
);
</script>
<template>
</template>
50 連鎖用グローバルストア設定
type Quantum = number;
const initialValue: Quantum = 0;
export const _vueQuantum = {
server: {
vueQuantumContextStart: (): Quantum => initialValue,
vueSetQuantumContextStart: (_: Quantum) => {},
vueQuantumStoreStart: (): Quantum => initialValue,
vueSetQuantumStoreStart: (_: Quantum) => {},
vueQuantum01: (): Quantum => initialValue,
vueSetQuantum01: (_: Quantum) => {},
},
client: () => {
const vueQuantumContextStart = ref<Quantum>(initialValue);
const vueSetQuantumContextStart = (value: Quantum) => { vueQuantumContextStart.value = value; };
const vueQuantumStoreStart = ref<Quantum>(initialValue);
const vueSetQuantumStoreStart = (value: Quantum) => { vueQuantumStoreStart.value = value; };
const vueQuantum01 = ref<Quantum>(initialValue);
const vueSetQuantum01 = (value: Quantum) => { vueQuantum01.value = value; };
return {
vueQuantumContextStart: () => vueQuantumContextStart.value, vueSetQuantumContextStart,
vueQuantumStoreStart: () => vueQuantumStoreStart.value, vueSetQuantumStoreStart,
vueQuantum01: () => vueQuantum01.value, vueSetQuantum01,
};
},
};
50 連鎖用 Context 設定
<script lang="ts">
type QuantumData = number;
const initialValue: QuantumData = 0;
type QuantumDataRef = Ref<QuantumData>;
const QuantumDataSymbol01: InjectionKey<QuantumDataRef> = Symbol();
const provideQuantumData = (value: QuantumDataRef) => {
provide(QuantumDataSymbol01, value);
};
export const useQuantumDataContexts = () => {
const injected01 = inject(QuantumDataSymbol01);
if (!injected01 || !injected02 || !injected03 || !injected04 || !injected05 || !injected06 || !injected07 || !injected08 || !injected09 || !injected10) {
return {
quantumData01: readonly({ value: initialValue }),
setQuantumData01: (_: QuantumData) => {},
}
};
const quantumData01 = readonly(injected01);
const setQuantumData01 = (value: QuantumData) => { injected01.value = value; };
return {
quantumData01, setQuantumData01,
};
};
export default defineComponent({
name: 'Quantum',
props: {
quantum01: {
type: Number as PropType<QuantumData>,
default: initialValue,
},
},
setup(props) {
provide(QuantumDataSymbol01, ref(props.quantum01));
}
});
</script>
<template>
<slot />
</template>
QuantumStart.vue
<script setup lang="ts">
const { vueSetQuantumStoreStart, vueSetQuantumContextStart } = useStore('vueQuantum');
const handleClick = () => {
vueSetQuantumContextStart(1);
vueSetQuantumStoreStart(1);
};
</script>
<template>
<fieldset>
<button @click="handleClick">50 連鎖スタート</button>
</fieldset>
</template>
QuantumCircuit.vue
<template>
<QuantumContext>
<Quantum00 />
// 10 まで同じ構造が続きます
</QuantumContext>
</template>
_quantumContexts/Quantum00.vue
<script setup lang="ts">
const { vueQuantumContextStart } = useStore('vueQuantum');
const { setQuantumData01 } = useQuantumDataContexts();
watch(
() => vueQuantumContextStart(),
() => {
if (!vueQuantumContextStart()) return;
recordStart('QuantumContext');
setQuantumData01(vueQuantumContextStart());
},
{ immediate: true }
);
</script>
<template>
</template>
_quantumContexts/Quantum01.vue
<script setup lang="ts">
const { quantumData01, setQuantumData02 } = useQuantumDataContexts();
watch(
() => quantumData01.value,
() => {
if (!quantumData01.value) return;
setQuantumData02(quantumData01.value);
},
{ immediate: true }
);
</script>
<template>
</template>
_quantumContexts/Quantum10.vue
<script setup lang="ts">
const { vueSetQuantumContextStart } = useStore('vueQuantum');
const { setQuantumData01, quantumData10 } = useQuantumDataContexts();
const incrementContext = (value: number) => {
setQuantumData01(value + 1);
};
watch(
() => quantumData10.value,
() => {
if (!quantumData10.value) return;
if (quantumData10.value >= loopTotal) {
recordFinished('QuantumContext');
vueSetQuantumContextStart(0);
return;
}
incrementContext(quantumData10.value);
},
{ immediate: true }
);
</script>
<template>
</template>
_quantumStores/Quantum00.vue
<script setup lang="ts">
const { vueQuantumStoreStart, vueSetQuantum01 } = useStore('vueQuantum');
watch(
() => vueQuantumStoreStart(),
() => {
if (!vueQuantumStoreStart()) return;
recordStart('QuantumStore');
vueSetQuantum01(vueQuantumStoreStart());
},
{ immediate: true }
);
</script>
<template>
</template>
_quantumStores/Quantum01.vue
<script setup lang="ts">
const { vueQuantum01, vueSetQuantum02 } = useStore('vueQuantum');
watch(
() => vueQuantum01(),
() => {
if (!vueQuantum01()) return;
vueSetQuantum02(vueQuantum01());
},
{ immediate: true }
);
</script>
<template>
</template>
_quantumStores/Quantum10.vue
<script setup lang="ts">
const { vueSetQuantumStoreStart, vueSetQuantum01, vueQuantum10 } = useStore('vueQuantum');
const incrementStore = (value: number) => {
vueSetQuantum01(value + 1);
};
watch(
() => vueQuantum10(),
() => {
if (!vueQuantum10()) return;
if (vueQuantum10() >= loopTotal) {
recordFinished('QuantumStore');
vueSetQuantumStoreStart(0);
return;
}
incrementStore(vueQuantum10());
},
{ immediate: true }
);
</script>
<template>
</template>
React 版
最深部からの伝播用グローバルストア設定
const initialValue = 0;
let relay = initialValue;
type Relay = typeof relay;
let listeners: (() => void)[] = [];
type Listener = (typeof listeners)[number];
export const reactRelayStore = {
setRelay(value: Relay) {
relay = value;
emitChange();
},
subscribe(listener: Listener) {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter(l => l !== listener);
};
},
getSnapshot() {
return relay;
},
getServerSnapshot() {
return initialValue;
}
};
const emitChange = () => {
for (let listener of listeners) {
listener();
}
};
最深部からの伝播用 Context 設定
import { createContext } from "react";
import type { RelayData } from "./types";
export const RelayContext = createContext({
relayContext: 0,
setRelayContext: (_: RelayData) => {},
});
Parent.tsx
export default function Parent() {
const [ relayContext, setRelayContext ] = useState(0);
return (
RelayContext value={{ relayContext, setRelayContext }}
Child00
RelayContext
)
};
Child00.tsx
export default function Child00() {
const { relayContext } = useContext(RelayContext);
const relayStore = useSyncExternalStore(reactRelayStore.subscribe, reactRelayStore.getSnapshot, reactRelayStore.getServerSnapshot);
const [ relay, setRelay ] = useState<RelayData>(0);
useEffect(() => {
if (!relay) return;
recordFinished('RelaySetter');
}, [ relay ]);
useEffect(() => {
if (!relayContext) return;
recordFinished('RelayContext');
}, [ relayContext ]);
useEffect(() => {
if (!relayStore) return;
recordFinished('RelayStore');
}, [ relayStore ]);
return Child01 relay={ relay } setRelay={ setRelay } ;
};
Child01.tsx
export default function Child01(props: RelayProps) {
return Child02 relay={ props.relay } setRelay={ props.setRelay } ;
};
Child10.tsx
export default function Child10(props: RelayProps) {
const { relayContext, setRelayContext } = useContext(RelayContext);
const handleChange = () => {
const start = relayContext + 1;
recordStart('RelaySetter');
props.setRelay(start);
recordStart('RelayContext');
setRelayContext(start);
recordStart('RelayStore');
reactRelayStore.setRelay(start);
};
return (
fieldset
input type="number" onChange={ handleChange } value={ props.relay }
fieldset
);
};
10 連鎖用グローバルストア設定
const initialValue = 0;
let raceNo = initialValue;
type RaceNo = typeof raceNo;
let listeners: (() => void)[] = [];
type Listener = (typeof listeners)[number];
export const reactRaceNoStore = {
setRaceNo(value: RaceNo) {
raceNo = value;
emitChange();
},
subscribe(listener: Listener) {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter(l => l !== listener);
};
},
getSnapshot() {
return raceNo;
},
getServerSnapshot() {
return initialValue;
}
};
const emitChange = () => {
for (let listener of listeners) {
listener();
}
};
Circuit.tsx
export default function Circuit() {
const raceNoStore = useSyncExternalStore(reactRaceNoStore.subscribe, reactRaceNoStore.getSnapshot, reactRaceNoStore.getServerSnapshot);
const handleClick = () => {
reactRaceNoStore.setRaceNo(raceNoStore + 1);
};
return (
fieldset
button onClick={ handleClick }10 連鎖スタートbutton
fieldset
)
}
RaceEffect.tsx
useEffect() で繋いでいくコンポーネントです。
export default function RaceEffect() {
const raceNoStore = useSyncExternalStore(reactRaceNoStore.subscribe, reactRaceNoStore.getSnapshot, reactRaceNoStore.getServerSnapshot);
const [ state01, setState01 ] = useState(0);
useEffect(() => {
if (!raceNoStore) return;
recordStart('RaceEffectState');
setState01(prev => prev + 1);
}, [ raceNoStore ]);
useEffect(() => {
if (!state01) return;
setState02(prev => prev + 1);
}, [ state01 ]);
useEffect(() => {
if (!state10) return;
recordFinished('RaceEffectState');
}, [ state10 ]);
return null;
}
RaceMemo.tsx
useMemo() で繋いでいくコンポーネントです。
export default function RaceMemo() {
const raceNoStore = useSyncExternalStore(reactRaceNoStore.subscribe, reactRaceNoStore.getSnapshot, reactRaceNoStore.getServerSnapshot);
const state01 = useMemo(() => {
if (!raceNoStore) return;
recordStart('RaceMemoState');
return raceNoStore + 1;
}, [ raceNoStore ]);
const state02 = useMemo(() => {
if (!state01) return;
return state01;
}, [ state01 ]);
useMemo(() => {
if (!state10) return;
recordFinished('RaceMemoState');
}, [ state10 ]);
return null;
}
RaceLayoutEffect.tsx
useLayoutEffect() で繋いでいくコンポーネントです。
export default function RaceLayoutEffect() {
const raceNoStore = useSyncExternalStore(reactRaceNoStore.subscribe, reactRaceNoStore.getSnapshot, reactRaceNoStore.getServerSnapshot);
const [ state01, setState01 ] = useState(0);
useLayoutEffect(() => {
if (!raceNoStore) return;
recordStart('RaceLayoutEffectState');
setState01(prev => prev + 1);
}, [ raceNoStore ]);
useLayoutEffect(() => {
if (!state01) return;
setState02(prev => prev + 1);
}, [ state01 ]);
useLayoutEffect(() => {
if (!state10) return;
recordFinished('RaceLayoutEffectState');
}, [ state10 ]);
return null;
}
50 連鎖用グローバルストア設定
const initialValue = 0 as number;
type Quantum = typeof initialValue;
let quantumContextStart = initialValue;
let quantumStoreStart = initialValue;
let quantum01 = initialValue;
type Listener = () => void;
let listenersContextStart: Listener[] = [];
let listenersStoreStart: Listener[] = [];
let listeners01: Listener[] = [];
export const reactQuantumContextStart = {
subscribe(listener: Listener) {
listenersContextStart = [...listenersContextStart, listener];
return () => {
listenersContextStart = listenersContextStart.filter(l => l !== listener);
};
},
getServerSnapshot() { return initialValue; },
setQuantumContextStart(value: Quantum) {
quantumContextStart = value;
for (let listener of listenersContextStart) {
listener();
}
},
getSnapshot() { return quantumContextStart; },
};
export const reactQuantumStoreStart = {
subscribe(listener: Listener) {
listenersStoreStart = [...listenersStoreStart, listener];
return () => {
listenersStoreStart = listenersStoreStart.filter(l => l !== listener);
};
},
getServerSnapshot() { return initialValue; },
setQuantumStoreStart(value: Quantum) {
quantumStoreStart = value;
for (let listener of listenersStoreStart) {
listener();
}
},
getSnapshot() { return quantumStoreStart; },
};
export const reactQuantum01Store = {
subscribe(listener: Listener) {
listeners01 = [...listeners01, listener];
return () => {
listeners01 = listeners01.filter(l => l !== listener);
};
},
getServerSnapshot() { return initialValue; },
setQuantum01(value: Quantum) {
quantum01 = value;
for (let listener of listeners01) {
listener();
}
},
getSnapshot() { return quantum01; },
};
50 連鎖用 Context 設定
export type QuantumData = number;
export const QuantumContext = createContext({
quantumData01: 0,
setQuantumData01: (_: QuantumData) => {},
});
QuantumStart.tsx
export default function QuantumStart() {
const handleClick = () => {
reactQuantumContextStart.setQuantumContextStart(1);
reactQuantumStoreStart.setQuantumStoreStart(1);
};
return (
fieldset
button onClick={ handleClick }50 連鎖スタートbutton
fieldset
)
}
QuantumCircuit.tsx
export default function QuantumCircuit() {
const [ quantumData01, setQuantumData01 ] = useState(0);
return (
QuantumContext value={{
quantumData01, setQuantumData01,
}}
Quantum00
// 10 まで同じ構造が続きます
QuantumContext
)
}
_quantumContexts/Quantum00.tsx
export default function Quantum00() {
const quantumStore = useSyncExternalStore(reactQuantumContextStart.subscribe, reactQuantumContextStart.getSnapshot, reactQuantumContextStart.getServerSnapshot);
const { setQuantumData01 } = useContext(QuantumContext);
useLayoutEffect(() => {
if (!quantumStore) return;
recordStart('QuantumContext');
setQuantumData01(quantumStore);
}, [ quantumStore ]);
return null;
}
_quantumContexts/Quantum01.tsx
export default function Quantum01() {
const { quantumData01, setQuantumData02 } = useContext(QuantumContext);
useLayoutEffect(() => {
if (!quantumData01) return;
setQuantumData02(quantumData01);
}, [ quantumData01 ]);
return null;
}
_quantumContexts/Quantum10.tsx
export default function Quantum10() {
const { setQuantumData01, quantumData10 } = useContext(QuantumContext);
const incrementContext = (value: number) => {
setQuantumData01(value + 1);
};
useLayoutEffect(() => {
if (!quantumData10) return;
if (quantumData10 >= loopTotal) {
recordFinished('QuantumContext');
reactQuantumContextStart.setQuantumContextStart(0);
return;
}
incrementContext(quantumData10);
}, [ quantumData10 ]);
return null;
}
_quantumStores/Quantum00.tsx
export default function Quantum00() {
const quantumStore = useSyncExternalStore(reactQuantumStoreStart.subscribe, reactQuantumStoreStart.getSnapshot, reactQuantumStoreStart.getServerSnapshot);
useLayoutEffect(() => {
if (!quantumStore) return;
recordStart('QuantumStore');
reactQuantum01Store.setQuantum01(quantumStore);
}, [ quantumStore ]);
return null;
}
_quantumStores/Quantum01.tsx
export default function Quantum01() {
const quantumStore = useSyncExternalStore(reactQuantum01Store.subscribe, reactQuantum01Store.getSnapshot, reactQuantum01Store.getServerSnapshot);
useLayoutEffect(() => {
if (!quantumStore) return;
reactQuantum02Store.setQuantum02(quantumStore);
}, [ quantumStore ]);
return null;
}
_quantumStores/Quantum10.tsx
export default function Quantum10() {
const quantumStore = useSyncExternalStore(reactQuantum10Store.subscribe, reactQuantum10Store.getSnapshot, reactQuantum10Store.getServerSnapshot);
const incrementStore = (value: number) => {
reactQuantum01Store.setQuantum01(value + 1);
};
useLayoutEffect(() => {
if (!quantumStore) return;
if (quantumStore >= loopTotal) {
recordFinished('QuantumStore');
reactQuantumStoreStart.setQuantumStoreStart(0);
return;
}
incrementStore(quantumStore);
}, [ quantumStore ]);
return null;
}
Qwik 版
Qwik ではグローバルストアを作る手段をまだ思いついていないため(Signal 設定はコンポーネント配下に置かなければならない)、Context で全て伝播しています。
最深部からの伝播用 Context 設定
export type RelayData = number;
export type RelaySetter = QRL<(_: RelayData) => void>;
export type RelayProps = {
relay: RelayData;
setRelay: RelaySetter;
};
export const relayData = createContextId<Signal<RelayData>>('relayData02');
Parent.tsx
export default component$(() => {
const relayDataSignal = useSignal<RelayData>(0);
useContextProvider(relayData, relayDataSignal);
return Child00 ;
});
Child00.tsx
export default component$(() => {
const relayDataContext = useContext(relayData);
const relay = useSignal(0);
const setRelay = $((value: RelayData) => { relay.value = value; });
useTask$(({ track }) => {
track(() => relayDataContext.value);
recordFinished('RelayContext');
});
useTask$(({ track }) => {
track(() => relay.value);
recordFinished('RelaySetter');
});
return Child01 relay={ relay.value } setRelay={ setRelay } ;
});
Child01.tsx
export default component$((props: RelayProps) => {
return Child02 relay={ props.relay } setRelay={ props.setRelay } ;
});
Child10.tsx
export default component$((props: RelayProps) => {
const relayDataContext = useContext(relayData);
const handleStartContext$ = $((value: number) => {
relayDataContext.value = value;
});
const handleStartSetter$ = $((value: number) => {
props.setRelay(value);
});
const handleChange$ = $((isActive: boolean = false) => {
if (!isActive) return;
const start = relayDataContext.value + 1;
recordStart('RelayContext');
handleStartContext$(start);
recordStart('RelaySetter');
handleStartSetter$(start);
});
useVisibleTask$(() => {
handleChange$();
});
return (
fieldset
input type="number" onChange$={ () => handleChange$(true) } value={ props.relay }
fieldset
);
});
10 連鎖コンポーネントの props 用型定義
export type RaceProps = {
start: number;
};
Circuit.tsx
export default component$(() => {
const start = useSignal(0);
const handleClick$ = $((isActive: boolean = false) => {
if (!isActive) return;
start.value++;
});
useVisibleTask$(() => {
handleClick$();
});
return (
fieldset
button onClick$={ () => handleClick$(true) }10 連鎖スタートbutton
RaceTask start={ start.value }
RaceComputed start={ start.value }
RaceVisibleTask start={ start.value }
fieldset
)
});
RaceTask.tsx
useTask$() で繋いでいくコンポーネントです。
export default component$((props: RaceProps) => {
const state01 = useSignal(0);
useTask$(({ track }) => {
track(() => props.start);
if (!props.start) return;
recordStart('RaceTaskState');
state01.value++;
});
useTask$(({ track }) => {
track(() => state01.value);
if (!state01.value) return;
state02.value++;
});
useTask$(({ track }) => {
track(() => state10.value);
if (!state10.value) return;
recordFinished('RaceTaskState');
});
return null;
});
RaceComputed.tsx
useComputed$() で繋いでいくコンポーネントです。
export default component$((props: RaceProps) => {
const state01 = useComputed$(() => {
if (!props.start) return;
recordStart('RaceComputedState');
return props.start + 1;
});
const state02 = useComputed$(() => {
if (!state01.value) return;
return state01.value;
});
useComputed$(() => {
if (!state10.value) return;
recordFinished('RaceComputedState');
});
return null;
});
RaceVisibleTask.tsx
useVisibleTask$() で繋いでいくコンポーネントです。
export default component$((props: RaceProps) => {
const state01 = useSignal(0);
useVisibleTask$(({ track }) => {
track(() => props.start);
if (!props.start) return;
recordStart('RaceVisibleTaskState');
state01.value++;
});
useVisibleTask$(({ track }) => {
track(() => state01.value);
if (!props.start || !state01.value) return;
state02.value++;
});
useVisibleTask$(({ track }) => {
track(() => state10.value);
if (!props.start || !state10.value) return;
recordFinished('RaceVisibleTaskState');
});
return null;
});
50 連鎖用 Context 設定
export type Quantum = number;
export type QuantumData = {
quantumStart: Signal<Quantum>;
quantum01: Signal<Quantum>;
};
export const quantumData = createContextId<QuantumData>('quantumData02');
QuantumStart.tsx
export default component$(() => {
const start = useSignal(0);
const handleClick$ = $((isActive: boolean = false) => {
if (!isActive) return;
start.value++;
});
useVisibleTask$(() => {
handleClick$();
});
return (
fieldset
button onClick$={ () => handleClick$(true) }50 連鎖スタートbutton
QuantumCircuit start={ start.value }
fieldset
)
});
QuantumCircuit.tsx
export default component$((props: RaceProps) => {
const quantumStart = useSignal<Quantum>(0);
const quantum01 = useSignal<Quantum>(0);
useContextProvider(quantumData, {
quantumStart: quantumStart,
quantum01: quantum01,
});
useTask$(({ track }) => {
track(() => props.start);
if (!props.start) return;
quantumStart.value = props.start;
});
return (
Quantum00
// 10 まで同じ構造が続きます
)
});
_quantumContexts/Quantum00.tsx
export default component$(() => {
const quantumDataContext = useContext(quantumData);
useTask$(({ track }) => {
track(() => quantumDataContext.quantumStart.value);
if (!quantumDataContext.quantumStart.value) return;
recordStart('QuantumContext');
quantumDataContext.quantum01.value = quantumDataContext.quantumStart.value;
});
return null;
});
_quantumContexts/Quantum01.tsx
export default component$(() => {
const quantumDataContext = useContext(quantumData);
useTask$(({ track }) => {
track(() => quantumDataContext.quantum01.value);
if (!quantumDataContext.quantum01.value) return;
quantumDataContext.quantum02.value = quantumDataContext.quantum01.value;
});
return null;
});
_quantumContexts/Quantum10.tsx
export default component$(() => {
const quantumDataContext = useContext(quantumData);
const incrementContext$ = $((value: number) => {
quantumDataContext.quantum01.value = value + 1;
});
useTask$(({ track }) => {
track(() => quantumDataContext.quantum10.value);
if (!quantumDataContext.quantum10.value) return;
if (quantumDataContext.quantum10.value >= loopTotal) {
recordFinished('QuantumContext');
quantumDataContext.quantumStart.value = 0;
return;
}
incrementContext$(quantumDataContext.quantum10.value);
});
return null;
});
計測結果
最深部からの伝播は冒頭の通り、テンプレート無し(React もこの構成なら最も速い Memo 無し)のみで Svelte のみ $bindable() も対象に加え、10 連鎖は各フレームワークにより対象の追加あり、50 連鎖もテンプレート無しに分離してあるので React は Memo 無しです。Qwik は開始の伝播も Context です。
Solid
1 回目
- RelaySetter: 0.20000004768371582 ミリ秒 / リロード直後
- RelaySetter: 0.19999992847442627 ミリ秒 / ウォームアップ後
- RelayContext: 0.10000002384185791 ミリ秒 / リロード直後
- RelayContext: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RelayStore: 0 ミリ秒 / リロード直後
- RelayStore: 0 ミリ秒 / ウォームアップ後
- RaceEffectState: 0 ミリ秒 / リロード直後
- RaceEffectState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RaceMemoState: 0 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 0.10000002384185791 ミリ秒 / リロード直後
- QuantumContext: 0.2999999523162842 ミリ秒 / ウォームアップ後
- QuantumStore: 0.10000002384185791 ミリ秒 / リロード直後
- QuantumStore: 0.10000002384185791 ミリ秒 / ウォームアップ後
2 回目
- RelaySetter: 0.2999999523162842 ミリ秒 / リロード直後
- RelaySetter: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RelayContext: 0 ミリ秒 / リロード直後
- RelayContext: 0 ミリ秒 / ウォームアップ後
- RelayStore: 0.10000002384185791 ミリ秒 / リロード直後
- RelayStore: 0 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceEffectState: 0 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 0.10000002384185791 ミリ秒 / リロード直後
- QuantumContext: 0.20000004768371582 ミリ秒 / ウォームアップ後
- QuantumStore: 0 ミリ秒 / リロード直後
- QuantumStore: 0.10000002384185791 ミリ秒 / ウォームアップ後
3 回目
- RelaySetter: 0.20000004768371582 ミリ秒 / リロード直後
- RelaySetter: 0.20000004768371582 ミリ秒 / ウォームアップ後
- RelayContext: 0 ミリ秒 / リロード直後
- RelayContext: 0 ミリ秒 / ウォームアップ後
- RelayStore: 0 ミリ秒 / リロード直後
- RelayStore: 0 ミリ秒 / ウォームアップ後
- RaceEffectState: 0 ミリ秒 / リロード直後
- RaceEffectState: 0 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.09999990463256836 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 0.20000004768371582 ミリ秒 / リロード直後
- QuantumContext: 0.19999992847442627 ミリ秒 / ウォームアップ後
- QuantumStore: 0.09999990463256836 ミリ秒 / リロード直後
- QuantumStore: 0.10000002384185791 ミリ秒 / ウォームアップ後
平均
- RelaySetter: 0.2333333492 ミリ秒 / リロード直後
- RelaySetter: 0.1666666667 ミリ秒 / ウォームアップ後
- RelayContext: 0.03333334128 ミリ秒 / リロード直後
- RelayContext: 0.03333334128 ミリ秒 / ウォームアップ後
- RelayStore: 0.03333334128 ミリ秒 / リロード直後
- RelayStore: 0 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.03333334128 ミリ秒 / リロード直後
- RaceEffectState: 0.03333334128 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.06666664282 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 0.1333333651 ミリ秒 / リロード直後
- QuantumContext: 0.2333333095 ミリ秒 / ウォームアップ後
- QuantumStore: 0.06666664282 ミリ秒 / リロード直後
- QuantumStore: 0.1000000238 ミリ秒 / ウォームアップ後
Svelte
1 回目
- RelayBindable: 0 ミリ秒 / リロード直後
- RelayBindable: 0 ミリ秒 / ウォームアップ後
- RelaySetter: 0.2999999523162842 ミリ秒 / リロード直後
- RelaySetter: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RelayContext: 0.3999999761581421 ミリ秒 / リロード直後
- RelayContext: 0.20000004768371582 ミリ秒 / ウォームアップ後
- RelayStore: 0.30000007152557373 ミリ秒 / リロード直後
- RelayStore: 0.30000007152557373 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.5 ミリ秒 / リロード直後
- RaceEffectState: 0.09999990463256836 ミリ秒 / ウォームアップ後
- RaceDerivedState: 0.09999990463256836 ミリ秒 / リロード直後
- RaceDerivedState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 1.399999976158142 ミリ秒 / リロード直後
- QuantumContext: 0.6000000238418579 ミリ秒 / ウォームアップ後
- QuantumStore: 1.899999976158142 ミリ秒 / リロード直後
- QuantumStore: 1 ミリ秒 / ウォームアップ後
2 回目
- RelayBindable: 0 ミリ秒 / リロード直後
- RelayBindable: 0 ミリ秒 / ウォームアップ後
- RelaySetter: 0.2999999523162842 ミリ秒 / リロード直後
- RelaySetter: 0.09999990463256836 ミリ秒 / ウォームアップ後
- RelayContext: 0.30000007152557373 ミリ秒 / リロード直後
- RelayContext: 0.19999992847442627 ミリ秒 / ウォームアップ後
- RelayStore: 0.10000002384185791 ミリ秒 / リロード直後
- RelayStore: 0.3999999761581421 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.2999999523162842 ミリ秒 / リロード直後
- RaceEffectState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RaceDerivedState: 0 ミリ秒 / リロード直後
- RaceDerivedState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 1.2999999523162842 ミリ秒 / リロード直後
- QuantumContext: 1.2999999523162842 ミリ秒 / ウォームアップ後
- QuantumStore: 1.8000000715255737 ミリ秒 / リロード直後
- QuantumStore: 1.899999976158142 ミリ秒 / ウォームアップ後
3 回目
- RelayBindable: 0 ミリ秒 / リロード直後
- RelayBindable: 0 ミリ秒 / ウォームアップ後
- RelaySetter: 0.5999999046325684 ミリ秒 / リロード直後
- RelaySetter: 0.09999990463256836 ミリ秒 / ウォームアップ後
- RelayContext: 0.8000000715255737 ミリ秒 / リロード直後
- RelayContext: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RelayStore: 0.5 ミリ秒 / リロード直後
- RelayStore: 0.30000007152557373 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.3999999761581421 ミリ秒 / リロード直後
- RaceEffectState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RaceDerivedState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceDerivedState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- QuantumContext: 1.2999999523162842 ミリ秒 / リロード直後
- QuantumContext: 1.399999976158142 ミリ秒 / ウォームアップ後
- QuantumStore: 1.6999999284744263 ミリ秒 / リロード直後
- QuantumStore: 1.899999976158142 ミリ秒 / ウォームアップ後
平均
- RelayBindable: 0 ミリ秒 / リロード直後
- RelayBindable: 0 ミリ秒 / ウォームアップ後
- RelaySetter: 0.3999999364 ミリ秒 / リロード直後
- RelaySetter: 0.09999994437 ミリ秒 / ウォームアップ後
- RelayContext: 0.5000000397 ミリ秒 / リロード直後
- RelayContext: 0.1666666667 ミリ秒 / ウォームアップ後
- RelayStore: 0.3000000318 ミリ秒 / リロード直後
- RelayStore: 0.3333333731 ミリ秒 / ウォームアップ後
- RaceEffectState: 0.3999999762 ミリ秒 / リロード直後
- RaceEffectState: 0.09999998411 ミリ秒 / ウォームアップ後
- RaceDerivedState: 0.06666664282 ミリ秒 / リロード直後
- RaceDerivedState: 0.03333334128 ミリ秒 / ウォームアップ後
- QuantumContext: 1.3333332936 ミリ秒 / リロード直後
- QuantumContext: 1.09999998411 ミリ秒 / ウォームアップ後
- QuantumStore: 1.7999999921 ミリ秒 / リロード直後
- QuantumStore: 1.5999999841 ミリ秒 / ウォームアップ後
Vue
1 回目
- RelaySetter: 0.3999999761581421 ミリ秒 / リロード直後
- RelaySetter: 0.20000004768371582 ミリ秒 / ウォームアップ後
- RelayContext: 0.2999999523162842 ミリ秒 / リロード直後
- RelayContext: 0.30000007152557373 ミリ秒 / ウォームアップ後
- RelayStore: 0.3999999761581421 ミリ秒 / リロード直後
- RelayStore: 0.30000007152557373 ミリ秒 / ウォームアップ後
- RaceWatchState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceWatchState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RaceComputedState: 0 ミリ秒 / リロード直後
- RaceComputedState: 0 ミリ秒 / ウォームアップ後
- RaceWatchEffectState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceWatchEffectState: 0 ミリ秒 / ウォームアップ後
- QuantumContext: 0.5 ミリ秒 / リロード直後
- QuantumContext: 0.5 ミリ秒 / ウォームアップ後
- QuantumStore: 0.3999999761581421 ミリ秒 / リロード直後
- QuantumStore: 0.40000009536743164 ミリ秒 / ウォームアップ後
2 回目
- RelaySetter: 0.3999999761581421 ミリ秒 / リロード直後
- RelaySetter: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RelayContext: 0.2999999523162842 ミリ秒 / リロード直後
- RelayContext: 0.09999990463256836 ミリ秒 / ウォームアップ後
- RelayStore: 0.5 ミリ秒 / リロード直後
- RelayStore: 0.2999999523162842 ミリ秒 / ウォームアップ後
- RaceWatchState: 0 ミリ秒 / リロード直後
- RaceWatchState: 0 ミリ秒 / ウォームアップ後
- RaceComputedState: 0 ミリ秒 / リロード直後
- RaceComputedState: 0 ミリ秒 / ウォームアップ後
- RaceWatchEffectState: 0.19999992847442627 ミリ秒 / リロード直後
- RaceWatchEffectState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- QuantumContext: 0.2999999523162842 ミリ秒 / リロード直後
- QuantumContext: 0.19999992847442627 ミリ秒 / ウォームアップ後
- QuantumStore: 0.2999999523162842 ミリ秒 / リロード直後
- QuantumStore: 0.3999999761581421 ミリ秒 / ウォームアップ後
3 回目
- RelaySetter: 0.40000009536743164 ミリ秒 / リロード直後
- RelaySetter: 0.20000004768371582 ミリ秒 / ウォームアップ後
- RelayContext: 0.2999999523162842 ミリ秒 / リロード直後
- RelayContext: 0.19999992847442627 ミリ秒 / ウォームアップ後
- RelayStore: 0.2999999523162842 ミリ秒 / リロード直後
- RelayStore: 0.2999999523162842 ミリ秒 / ウォームアップ後
- RaceWatchState: 0.20000004768371582 ミリ秒 / リロード直後
- RaceWatchState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- RaceComputedState: 0 ミリ秒 / リロード直後
- RaceComputedState: 0.09999990463256836 ミリ秒 / ウォームアップ後
- RaceWatchEffectState: 0.20000004768371582 ミリ秒 / リロード直後
- RaceWatchEffectState: 0.10000002384185791 ミリ秒 / ウォームアップ後
- QuantumContext: 0.20000004768371582 ミリ秒 / リロード直後
- QuantumContext: 0.10000002384185791 ミリ秒 / ウォームアップ後
- QuantumStore: 0.5 ミリ秒 / リロード直後
- QuantumStore: 0.5 ミリ秒 / ウォームアップ後
平均
- RelaySetter: 0.4000000159 ミリ秒 / リロード直後
- RelaySetter: 0.1666667064 ミリ秒 / ウォームアップ後
- RelayContext: 0.2999999523 ミリ秒 / リロード直後
- RelayContext: 0.1999999682 ミリ秒 / ウォームアップ後
- RelayStore: 0.3999999762 ミリ秒 / リロード直後
- RelayStore: 0.2999999921 ミリ秒 / ウォームアップ後
- RaceWatchState: 0.1000000238 ミリ秒 / リロード直後
- RaceWatchState: 0.06666668256 ミリ秒 / ウォームアップ後
- RaceComputedState: 0 ミリ秒 / リロード直後
- RaceComputedState: 0.03333330154 ミリ秒 / ウォームアップ後
- RaceWatchEffectState: 0.1666666667 ミリ秒 / リロード直後
- RaceWatchEffectState: 0.06666668256 ミリ秒 / ウォームアップ後
- QuantumContext: 0.3333333333 ミリ秒 / リロード直後
- QuantumContext: 0.2666666508 ミリ秒 / ウォームアップ後
- QuantumStore: 0.3999999762 ミリ秒 / リロード直後
- QuantumStore: 0.4333333572 ミリ秒 / ウォームアップ後
React
1 回目
- RelaySetter: 2.600000023841858 ミリ秒 / リロード直後
- RelaySetter: 1.1999999284744263 ミリ秒 / ウォームアップ後
- RelayContext: 2.5 ミリ秒 / リロード直後
- RelayContext: 1.399999976158142 ミリ秒 / ウォームアップ後
- RelayStore: 2.600000023841858 ミリ秒 / リロード直後
- RelayStore: 1.399999976158142 ミリ秒 / ウォームアップ後
- RaceEffectState: 4.600000023841858 ミリ秒 / リロード直後
- RaceEffectState: 3.799999952316284 ミリ秒 / ウォームアップ後
- RaceMemoState: 0 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- RaceLayoutEffectState: 1.2000000476837158 ミリ秒 / リロード直後
- RaceLayoutEffectState: 0.9000000953674316 ミリ秒 / ウォームアップ後
- QuantumContext: 36.89999997615814 ミリ秒 / リロード直後
- QuantumContext: 31.09999990463257 ミリ秒 / ウォームアップ後
- QuantumStore: 6.600000023841858 ミリ秒 / リロード直後
- QuantumStore: 5.899999976158142 ミリ秒 / ウォームアップ後
2 回目
- RelaySetter: 3.100000023841858 ミリ秒 / リロード直後
- RelaySetter: 1.100000023841858 ミリ秒 / ウォームアップ後
- RelayContext: 3.100000023841858 ミリ秒 / リロード直後
- RelayContext: 1.100000023841858 ミリ秒 / ウォームアップ後
- RelayStore: 3.200000047683716 ミリ秒 / リロード直後
- RelayStore: 1.2999999523162842 ミリ秒 / ウォームアップ後
- RaceEffectState: 3.899999976158142 ミリ秒 / リロード直後
- RaceEffectState: 3.200000047683716 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- RaceLayoutEffectState: 1.1999999284744263 ミリ秒 / リロード直後
- RaceLayoutEffectState: 1 ミリ秒 / ウォームアップ後
- QuantumContext: 32.299999952316284 ミリ秒 / リロード直後
- QuantumContext: 31.300000071525574 ミリ秒 / ウォームアップ後
- QuantumStore: 6.5 ミリ秒 / リロード直後
- QuantumStore: 5.399999976158142 ミリ秒 / ウォームアップ後
3 回目
- RelaySetter: 3 ミリ秒 / リロード直後
- RelaySetter: 1.2000000476837158 ミリ秒 / ウォームアップ後
- RelayContext: 2.799999952316284 ミリ秒 / リロード直後
- RelayContext: 1.3000000715255737 ミリ秒 / ウォームアップ後
- RelayStore: 3 ミリ秒 / リロード直後
- RelayStore: 1.399999976158142 ミリ秒 / ウォームアップ後
- RaceEffectState: 5.600000023841858 ミリ秒 / リロード直後
- RaceEffectState: 3.100000023841858 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.10000002384185791 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- RaceLayoutEffectState: 2.600000023841858 ミリ秒 / リロード直後
- RaceLayoutEffectState: 1.1999999284744263 ミリ秒 / ウォームアップ後
- QuantumContext: 34.199999928474426 ミリ秒 / リロード直後
- QuantumContext: 29.899999976158142 ミリ秒 / ウォームアップ後
- QuantumStore: 6.800000071525574 ミリ秒 / リロード直後
- QuantumStore: 6.300000071525574 ミリ秒 / ウォームアップ後
平均
- RelaySetter: 2.9000000159 ミリ秒 / リロード直後
- RelaySetter: 1.1666666667 ミリ秒 / ウォームアップ後
- RelayContext: 2.7999999921 ミリ秒 / リロード直後
- RelayContext: 1.2666666905 ミリ秒 / ウォームアップ後
- RelayStore: 2.9333333572 ミリ秒 / リロード直後
- RelayStore: 1.3666666349 ミリ秒 / ウォームアップ後
- RaceEffectState: 4.7000000079 ミリ秒 / リロード直後
- RaceEffectState: 3.3666666746 ミリ秒 / ウォームアップ後
- RaceMemoState: 0.06666668256 ミリ秒 / リロード直後
- RaceMemoState: 0 ミリ秒 / ウォームアップ後
- RaceLayoutEffectState: 1.6666666667 ミリ秒 / リロード直後
- RaceLayoutEffectState: 1.03333334128 ミリ秒 / ウォームアップ後
- QuantumContext: 34.466666619 ミリ秒 / リロード直後
- QuantumContext: 30.7666666508 ミリ秒 / ウォームアップ後
- QuantumStore: 6.6333333651 ミリ秒 / リロード直後
- QuantumStore: 5.8666666746 ミリ秒 / ウォームアップ後
Qwik
1 回目
- RelaySetter: 6.5 ミリ秒 / QRL ダウンロード含む
- RelaySetter: 1.0999999046325684 ミリ秒 / QRL ダウンロード後
- RelayContext: 4.600000023841858 ミリ秒 / QRL ダウンロード含む
- RelayContext: 1.100000023841858 ミリ秒 / QRL ダウンロード後
- RaceTaskState: 19.5 ミリ秒 / QRL ダウンロード含む
- RaceTaskState: 0.3999999761581421 ミリ秒 / QRL ダウンロード後
- RaceComputedState: 19.5 ミリ秒 / QRL ダウンロード含む
- RaceComputedState: 0.3999999761581421 ミリ秒 / QRL ダウンロード後
- RaceVisibleTaskState: 0.2999999523162842 ミリ秒 / QRL ダウンロード後
- QuantumContext: 18 ミリ秒 / QRL ダウンロード含む
- QuantumContext: 1.2999999523162842 ミリ秒 / QRL ダウンロード後
2 回目
- RelaySetter: 6.899999976158142 ミリ秒 / QRL ダウンロード含む
- RelaySetter: 1 ミリ秒 / QRL ダウンロード後
- RelayContext: 4.799999952316284 ミリ秒 / QRL ダウンロード含む
- RelayContext: 0.7999999523162842 ミリ秒 / QRL ダウンロード後
- RaceTaskState: 25.399999976158142 ミリ秒 / QRL ダウンロード含む
- RaceTaskState: 0.5 ミリ秒 / QRL ダウンロード後
- RaceComputedState: 25.300000071525574 ミリ秒 / QRL ダウンロード含む
- RaceComputedState: 0.5999999046325684 ミリ秒 / QRL ダウンロード後
- RaceVisibleTaskState: 0.3999999761581421 ミリ秒 / QRL ダウンロード後
- QuantumContext: 15.799999952316284 ミリ秒 / QRL ダウンロード含む
- QuantumContext: 1 ミリ秒 / QRL ダウンロード後
3 回目
- RelaySetter: 5.700000047683716 ミリ秒 / QRL ダウンロード含む
- RelaySetter: 0.8999999761581421 ミリ秒 / QRL ダウンロード後
- RelayContext: 3.600000023841858 ミリ秒 / QRL ダウンロード含む
- RelayContext: 0.8999999761581421 ミリ秒 / QRL ダウンロード後
- RaceTaskState: 21.800000071525574 ミリ秒 / QRL ダウンロード含む
- RaceTaskState: 0.40000009536743164 ミリ秒 / QRL ダウンロード後
- RaceComputedState: 21.899999976158142 ミリ秒 / QRL ダウンロード含む
- RaceComputedState: 0.7000000476837158 ミリ秒 / QRL ダウンロード後
- RaceVisibleTaskState: 0.2999999523162842 ミリ秒 / QRL ダウンロード後
- QuantumContext: 14.799999952316284 ミリ秒 / QRL ダウンロード含む
- QuantumContext: 0.8999999761581421 ミリ秒 / QRL ダウンロード後
平均
- RelaySetter: 6.3666666746 ミリ秒 / QRL ダウンロード含む
- RelaySetter: 0.9999999603 ミリ秒 / QRL ダウンロード後
- RelayContext: 4.3333333333 ミリ秒 / QRL ダウンロード含む
- RelayContext: 0.9333333174 ミリ秒 / QRL ダウンロード後
- RaceTaskState: 22.2333333492 ミリ秒 / QRL ダウンロード含む
- RaceTaskState: 0.4333333572 ミリ秒 / QRL ダウンロード後
- RaceComputedState: 22.2333333492 ミリ秒 / QRL ダウンロード含む
- RaceComputedState: 0.5666666428 ミリ秒 / QRL ダウンロード後
- RaceVisibleTaskState: 0.3333332936 ミリ秒 / QRL ダウンロード後
- QuantumContext: 16.1999999682 ミリ秒 / QRL ダウンロード含む
- QuantumContext: 1.06666664282 ミリ秒 / QRL ダウンロード後
RelaySetter
Svelte の $bindable() での伝播は、「同じ props を使う」ということで RelaySetter と同じ枠で扱うことにしました。
- Svelte Bindable リロード直後 / Svelte Bindable ウォームアップ後: 0 ミリ秒
- Svelte Setter ウォームアップ後: 0.09999994437 ミリ秒
- Solid ウォームアップ後: 0.1666666667 ミリ秒
- Vue ウォームアップ後: 0.1666667064 ミリ秒
- Solid リロード直後: 0.2333333492 ミリ秒
- Svelte Setter リロード直後: 0.3999999364 ミリ秒
- Vue リロード直後: 0.4000000159 ミリ秒
- Qwik QRL ダウンロード後: 0.9999999603 ミリ秒
- React ウォームアップ後: 1.1666666667 ミリ秒
- React リロード直後: 2.9000000159 ミリ秒
- Qwik QRL ダウンロード含む: 6.3666666746 ミリ秒
RelayContext
- Solid リロード直後 / Solid ウォームアップ後: 0.03333334128 ミリ秒
- Svelte ウォームアップ後: 0.1666666667 ミリ秒
- Vue ウォームアップ後: 0.1999999682 ミリ秒
- Vue リロード直後: 0.2999999523 ミリ秒
- Svelte リロード直後: 0.5000000397 ミリ秒
- Qwik QRL ダウンロード後: 0.9333333174 ミリ秒
- React ウォームアップ後: 1.2666666905 ミリ秒
- React リロード直後: 2.7999999921 ミリ秒
- Qwik QRL ダウンロード含む: 4.3333333333 ミリ秒
RelayStore
- Solid ウォームアップ後: 0 ミリ秒
- Solid リロード直後: 0.03333334128 ミリ秒
- Vue ウォームアップ後: 0.2999999921 ミリ秒
- Svelte リロード直後: 0.3000000318 ミリ秒
- Svelte ウォームアップ後: 0.3333333731 ミリ秒
- Vue リロード直後: 0.3999999762 ミリ秒
- React ウォームアップ後: 1.3666666349 ミリ秒
- React リロード直後: 2.9333333572 ミリ秒
RaceEffectState
Memo 系以外を同じ枠で扱うことにしました。
- Solid Effect リロード直後 / Solid Effect ウォームアップ後 / Vue Watch リロード直後: 0.03333334128 ミリ秒
- Vue WatchEffect ウォームアップ後: 0.06666668256 ミリ秒
- Svelte Effect ウォームアップ後 / Vue Watch ウォームアップ後: 0.09999998411 ミリ秒
- Vue WatchEffect リロード直後: 0.1000000238 ミリ秒
- Qwik VisibleTask QRL ダウンロード後: 0.3333332936 ミリ秒
- Svelte Effect リロード直後: 0.3999999762 ミリ秒
- Qwik Task QRL ダウンロード後: 0.4333333572 ミリ秒
- React LayoutEffect ウォームアップ後: 1.03333334128 ミリ秒
- React LayoutEffect リロード直後: 1.6666666667 ミリ秒
- React Effect ウォームアップ後: 3.3666666746 ミリ秒
- React Effect リロード直後: 4.7000000079 ミリ秒
- Qwik Task QRL ダウンロード含む: 22.2333333492 ミリ秒
RaceMemoState
- Solid ウォームアップ後 / Vue リロード直後 / React ウォームアップ後: 0 ミリ秒
- Vue ウォームアップ後: 0.03333330154 ミリ秒
- Svelte ウォームアップ後: 0.03333334128 ミリ秒
- Solid リロード直後 / Svelte リロード直後: 0.06666664282 ミリ秒
- React リロード直後: 0.06666668256 ミリ秒
- Qwik QRL ダウンロード後: 0.5666666428 ミリ秒
- Qwik QRL ダウンロード含む: 22.2333333492 ミリ秒
QuantumContext
- Solid リロード直後: 0.1333333651 ミリ秒
- Solid ウォームアップ後: 0.2333333095 ミリ秒
- Vue ウォームアップ後: 0.2666666508 ミリ秒
- Vue リロード直後: 0.3333333333 ミリ秒
- Qwik QRL ダウンロード後: 1.06666664282 ミリ秒
- Svelte ウォームアップ後: 1.09999998411 ミリ秒
- Svelte リロード直後: 1.3333332936 ミリ秒
- Qwik QRL ダウンロード含む: 16.1999999682 ミリ秒
- React ウォームアップ後: 30.7666666508 ミリ秒
- React リロード直後: 34.466666619 ミリ秒
QuantumStore
- Solid: 0.06666664282 ミリ秒 / リロード直後
- Solid: 0.1000000238 ミリ秒 / ウォームアップ後
- Vue: 0.3999999762 ミリ秒 / リロード直後
- Vue: 0.4333333572 ミリ秒 / ウォームアップ後
- Svelte: 1.5999999841 ミリ秒 / ウォームアップ後
- Svelte: 1.7999999921 ミリ秒 / リロード直後
- React: 5.8666666746 ミリ秒 / ウォームアップ後
- React: 6.6333333651 ミリ秒 / リロード直後
第 3 回も、いずれも 3 回ずつの結果で、有意な数値とは言えませんが、この結果になりました。
興味があってやってみたところ、$bindable() が不動の 0 ミリ秒だったのが驚きました。
Qwik は使った関数をシリアライズし直して、また使う際に解凍するらしいので、電撃数値が出ないのは仕方ないのかなと思います。ハイドレーションをしない代わり...という感じでしょうか。
今回も、とても面白い実験でした。