@@ -19,6 +19,15 @@ import { active_effect, get } from './runtime.js';
1919
2020const array_methods = [ 'push' , 'pop' , 'shift' , 'unshift' , 'splice' , 'reverse' , 'sort' ] ;
2121
22+ /**
23+ * Used to prevent batching in case we are not setting the length of an array
24+ * @param {any } fn
25+ * @returns
26+ */
27+ function identity ( fn ) {
28+ return fn ;
29+ }
30+
2231/**
2332 * @param {ValueOptions | undefined } options
2433 * @returns {ValueOptions | undefined }
@@ -306,46 +315,54 @@ export function proxy(value, _options, parent = null, prev) {
306315 var s = sources . get ( prop ) ;
307316 var has = prop in target ;
308317
309- // variable.length = value -> clear all signals with index >= value
310- if ( is_proxied_array && prop === 'length' ) {
311- for ( var i = value ; i < /** @type {Source<number> } */ ( s ) . v ; i += 1 ) {
312- var other_s = sources . get ( i + '' ) ;
313- if ( other_s !== undefined ) {
314- if ( typeof other_s . v === 'object' && other_s . v !== null && STATE_SYMBOL in other_s . v ) {
315- other_s . v [ PROXY_ONCHANGE_SYMBOL ] ( options ?. onchange , true ) ;
318+ // if we are changing the length of the array we batch all the changes
319+ // to the sources and the original value by calling batch_onchange and immediately
320+ // invoking it...otherwise we just invoke an identity function
321+ ( is_proxied_array && prop === 'length' ? batch_onchange : identity ) ( ( ) => {
322+ // variable.length = value -> clear all signals with index >= value
323+ if ( is_proxied_array && prop === 'length' ) {
324+ for ( var i = value ; i < /** @type {Source<number> } */ ( s ) . v ; i += 1 ) {
325+ var other_s = sources . get ( i + '' ) ;
326+ if ( other_s !== undefined ) {
327+ if (
328+ typeof other_s . v === 'object' &&
329+ other_s . v !== null &&
330+ STATE_SYMBOL in other_s . v
331+ ) {
332+ other_s . v [ PROXY_ONCHANGE_SYMBOL ] ( options ?. onchange , true ) ;
333+ }
334+ set ( other_s , UNINITIALIZED ) ;
335+ } else if ( i in target ) {
336+ // If the item exists in the original, we need to create a uninitialized source,
337+ // else a later read of the property would result in a source being created with
338+ // the value of the original item at that index.
339+ other_s = source ( UNINITIALIZED , clone_options ( options ) , stack ) ;
340+ sources . set ( i + '' , other_s ) ;
316341 }
317- set ( other_s , UNINITIALIZED ) ;
318- } else if ( i in target ) {
319- // If the item exists in the original, we need to create a uninitialized source,
320- // else a later read of the property would result in a source being created with
321- // the value of the original item at that index.
322- other_s = source ( UNINITIALIZED , clone_options ( options ) , stack ) ;
323- sources . set ( i + '' , other_s ) ;
324342 }
325343 }
326- }
327344
328- // If we haven't yet created a source for this property, we need to ensure
329- // we do so otherwise if we read it later, then the write won't be tracked and
330- // the heuristics of effects will be different vs if we had read the proxied
331- // object property before writing to that property.
332- if ( s === undefined ) {
333- if ( ! has || get_descriptor ( target , prop ) ?. writable ) {
334- const opt = clone_options ( options ) ;
335- s = source ( undefined , opt , stack ) ;
336- set ( s , proxy ( value , opt , metadata ) ) ;
337- sources . set ( prop , s ) ;
338- }
339- } else {
340- has = s . v !== UNINITIALIZED ;
341- // when we set a property if the source is a proxy we remove the current onchange from
342- // the proxy `onchanges` so that it doesn't trigger it anymore
343- if ( typeof s . v === 'object' && s . v !== null && STATE_SYMBOL in s . v ) {
344- s . v [ PROXY_ONCHANGE_SYMBOL ] ( options ?. onchange , true ) ;
345+ // If we haven't yet created a source for this property, we need to ensure
346+ // we do so otherwise if we read it later, then the write won't be tracked and
347+ // the heuristics of effects will be different vs if we had read the proxied
348+ // object property before writing to that property.
349+ if ( s === undefined ) {
350+ if ( ! has || get_descriptor ( target , prop ) ?. writable ) {
351+ const opt = clone_options ( options ) ;
352+ s = source ( undefined , opt , stack ) ;
353+ set ( s , proxy ( value , opt , metadata ) ) ;
354+ sources . set ( prop , s ) ;
355+ }
356+ } else {
357+ has = s . v !== UNINITIALIZED ;
358+ // when we set a property if the source is a proxy we remove the current onchange from
359+ // the proxy `onchanges` so that it doesn't trigger it anymore
360+ if ( typeof s . v === 'object' && s . v !== null && STATE_SYMBOL in s . v ) {
361+ s . v [ PROXY_ONCHANGE_SYMBOL ] ( options ?. onchange , true ) ;
362+ }
363+ set ( s , proxy ( value , clone_options ( options ) , metadata ) ) ;
345364 }
346- set ( s , proxy ( value , clone_options ( options ) , metadata ) ) ;
347- }
348-
365+ } ) ( ) ;
349366 if ( DEV ) {
350367 /** @type {ProxyMetadata | undefined } */
351368 var prop_metadata = value ?. [ STATE_SYMBOL_METADATA ] ;
0 commit comments