chore: improve $state.frozen performance in prod (#11852)

* chore: improve $state.frozen performance in prod

* lint

* feedback
pull/11858/head
Dominic Gannaway 8 months ago committed by GitHub
parent f411f776ca
commit 5f218b5f3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
chore: improve $state.frozen performance in prod

@ -18,4 +18,5 @@ export const EFFECT_TRANSPARENT = 1 << 15;
export const LEGACY_DERIVED_PROP = 1 << 16; export const LEGACY_DERIVED_PROP = 1 << 16;
export const STATE_SYMBOL = Symbol('$state'); export const STATE_SYMBOL = Symbol('$state');
export const STATE_FROZEN_SYMBOL = Symbol('$state.frozen');
export const LOADING_ATTR_SYMBOL = Symbol(''); export const LOADING_ATTR_SYMBOL = Symbol('');

@ -18,20 +18,25 @@ import {
} from './utils.js'; } from './utils.js';
import { check_ownership, widen_ownership } from './dev/ownership.js'; import { check_ownership, widen_ownership } from './dev/ownership.js';
import { mutable_source, source, set } from './reactivity/sources.js'; import { mutable_source, source, set } from './reactivity/sources.js';
import { STATE_SYMBOL } from './constants.js'; import { STATE_FROZEN_SYMBOL, STATE_SYMBOL } from './constants.js';
import { UNINITIALIZED } from '../../constants.js'; import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js'; import * as e from './errors.js';
/** /**
* @template T * @template T
* @param {T} value * @param {T} initial_value
* @param {boolean} [immutable] * @param {boolean} [immutable]
* @param {import('#client').ProxyMetadata | null} [parent] * @param {import('#client').ProxyMetadata | null} [parent]
* @param {import('#client').Source<T>} [prev] dev mode only * @param {import('#client').Source<T>} [prev] dev mode only
* @returns {import('#client').ProxyStateObject<T> | T} * @returns {import('#client').ProxyStateObject<T> | T}
*/ */
export function proxy(value, immutable = true, parent = null, prev) { export function proxy(initial_value, immutable = true, parent = null, prev) {
if (typeof value === 'object' && value != null && !is_frozen(value)) { if (typeof initial_value === 'object' && initial_value != null) {
let value = initial_value;
// If the object is frozen then snapshot the value
if (is_frozen(value) || STATE_FROZEN_SYMBOL in value) {
value = snapshot(value);
}
// If we have an existing proxy, return it... // If we have an existing proxy, return it...
if (STATE_SYMBOL in value) { if (STATE_SYMBOL in value) {
const metadata = /** @type {import('#client').ProxyMetadata<T>} */ (value[STATE_SYMBOL]); const metadata = /** @type {import('#client').ProxyMetadata<T>} */ (value[STATE_SYMBOL]);
@ -94,7 +99,7 @@ export function proxy(value, immutable = true, parent = null, prev) {
} }
} }
return value; return initial_value;
} }
/** /**

@ -1,5 +1,11 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { get_descriptors, get_prototype_of, is_frozen, object_freeze } from './utils.js'; import {
define_property,
get_descriptors,
get_prototype_of,
is_frozen,
object_freeze
} from './utils.js';
import { snapshot } from './proxy.js'; import { snapshot } from './proxy.js';
import { destroy_effect, effect, execute_effect_teardown } from './reactivity/effects.js'; import { destroy_effect, effect, execute_effect_teardown } from './reactivity/effects.js';
import { import {
@ -17,7 +23,8 @@ import {
BLOCK_EFFECT, BLOCK_EFFECT,
ROOT_EFFECT, ROOT_EFFECT,
LEGACY_DERIVED_PROP, LEGACY_DERIVED_PROP,
DISCONNECTED DISCONNECTED,
STATE_FROZEN_SYMBOL
} from './constants.js'; } from './constants.js';
import { flush_tasks } from './dom/task.js'; import { flush_tasks } from './dom/task.js';
import { add_owner } from './dev/ownership.js'; import { add_owner } from './dev/ownership.js';
@ -1353,19 +1360,26 @@ if (DEV) {
} }
/** /**
* Expects a value that was wrapped with `freeze` and makes it frozen. * Expects a value that was wrapped with `freeze` and makes it frozen in DEV.
* @template T * @template T
* @param {T} value * @param {T} value
* @returns {Readonly<T>} * @returns {Readonly<T>}
*/ */
export function freeze(value) { export function freeze(value) {
if (typeof value === 'object' && value != null && !is_frozen(value)) { if (typeof value === 'object' && value != null && !(STATE_FROZEN_SYMBOL in value)) {
// If the object is already proxified, then snapshot the value // If the object is already proxified, then snapshot the value
if (STATE_SYMBOL in value) { if (STATE_SYMBOL in value || is_frozen(value)) {
return object_freeze(snapshot(value)); value = snapshot(value);
}
define_property(value, STATE_FROZEN_SYMBOL, {
value: true,
writable: true,
enumerable: false
});
// Freeze the object in DEV
if (DEV) {
object_freeze(value);
} }
// Otherwise freeze the object
object_freeze(value);
} }
return value; return value;
} }

Loading…
Cancel
Save