Skip to content

Commit 7144f11

Browse files
committed
dry out
1 parent 591aeb0 commit 7144f11

File tree

5 files changed

+104
-119
lines changed

5 files changed

+104
-119
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ export function build_render_statement(state) {
155155
: b.block(state.update)
156156
),
157157
all.length > 0 && b.array(sync.map(({ expression }) => b.thunk(expression))),
158-
async.length > 0 && b.array(async.map(({ expression }) => b.thunk(expression, true))),
159-
!state.analysis.runes && sync.length > 0 && b.id('$.derived_safe_equal')
158+
async.length > 0 && b.array(async.map(({ expression }) => b.thunk(expression, true)))
160159
)
161160
);
162161
}
Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,24 @@
1-
/** @import { Effect, TemplateNode, Value } from '#client' */
2-
import { DESTROYED } from '#client/constants';
3-
import { async_derived } from '../../reactivity/deriveds.js';
4-
import { active_effect, get } from '../../runtime.js';
5-
import { capture, get_pending_boundary } from './boundary.js';
1+
/** @import { TemplateNode, Value } from '#client' */
2+
import { flatten } from '../../reactivity/async.js';
3+
import { get } from '../../runtime.js';
4+
import { get_pending_boundary } from './boundary.js';
65

76
/**
87
* @param {TemplateNode} node
98
* @param {Array<() => Promise<any>>} expressions
109
* @param {(anchor: TemplateNode, ...deriveds: Value[]) => void} fn
1110
*/
12-
export async function async(node, expressions, fn) {
13-
// TODO handle hydration
14-
15-
var parent = /** @type {Effect} */ (active_effect);
16-
17-
var restore = capture();
11+
export function async(node, expressions, fn) {
1812
var boundary = get_pending_boundary();
1913

14+
// TODO why is this necessary? doesn't it happen inside `async_derived` inside `flatten`?
2015
boundary.update_pending_count(1);
2116

22-
try {
23-
const deriveds = await Promise.all(expressions.map((fn) => async_derived(fn)));
24-
25-
// get deriveds eagerly to avoid creating blocks if they reject
26-
for (const d of deriveds) get(d);
27-
28-
if ((parent.f & DESTROYED) !== 0) return;
17+
flatten([], expressions, (values) => {
18+
// get values eagerly to avoid creating blocks if they reject
19+
for (const d of values) get(d);
2920

30-
restore();
31-
fn(node, ...deriveds);
32-
} catch (error) {
33-
boundary.error(error);
34-
} finally {
21+
fn(node, ...values);
3522
boundary.update_pending_count(-1);
36-
}
23+
});
3724
}

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { ATTACHMENT_KEY, NAMESPACE_HTML } from '../../../../constants.js';
2323
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
2424
import { derived } from '../../reactivity/deriveds.js';
2525
import { init_select, select_option } from './bindings/select.js';
26+
import { flatten } from '../../reactivity/async.js';
2627

2728
export const CLASS = Symbol('class');
2829
export const STYLE = Symbol('style');
@@ -473,72 +474,54 @@ export function attribute_effect(
473474
sync = [],
474475
async = [],
475476
css_hash,
476-
skip_warning = false,
477-
d = derived
478-
) {
479-
const deriveds = sync.map(d);
480-
481-
create_attribute_effect(element, fn, deriveds, css_hash, skip_warning);
482-
}
483-
484-
/**
485-
* @param {Element & ElementCSSInlineStyle} element
486-
* @param {(...expressions: any) => Record<string | symbol, any>} fn
487-
* @param {Value[]} deriveds
488-
* @param {string} [css_hash]
489-
* @param {boolean} [skip_warning]
490-
*/
491-
export function create_attribute_effect(
492-
element,
493-
fn,
494-
deriveds = [],
495-
css_hash,
496477
skip_warning = false
497478
) {
498-
/** @type {Record<string | symbol, any> | undefined} */
499-
var prev = undefined;
479+
flatten(sync, async, (values) => {
480+
/** @type {Record<string | symbol, any> | undefined} */
481+
var prev = undefined;
500482

501-
/** @type {Record<symbol, Effect>} */
502-
var effects = {};
483+
/** @type {Record<symbol, Effect>} */
484+
var effects = {};
503485

504-
var is_select = element.nodeName === 'SELECT';
505-
var inited = false;
486+
var is_select = element.nodeName === 'SELECT';
487+
var inited = false;
506488

507-
block(() => {
508-
var next = fn(...deriveds.map(get));
509-
/** @type {Record<string | symbol, any>} */
510-
var current = set_attributes(element, prev, next, css_hash, skip_warning);
489+
block(() => {
490+
var next = fn(...values.map(get));
491+
/** @type {Record<string | symbol, any>} */
492+
var current = set_attributes(element, prev, next, css_hash, skip_warning);
511493

512-
if (inited && is_select && 'value' in next) {
513-
select_option(/** @type {HTMLSelectElement} */ (element), next.value, false);
514-
}
494+
if (inited && is_select && 'value' in next) {
495+
select_option(/** @type {HTMLSelectElement} */ (element), next.value, false);
496+
}
515497

516-
for (let symbol of Object.getOwnPropertySymbols(effects)) {
517-
if (!next[symbol]) destroy_effect(effects[symbol]);
518-
}
498+
for (let symbol of Object.getOwnPropertySymbols(effects)) {
499+
if (!next[symbol]) destroy_effect(effects[symbol]);
500+
}
519501

520-
for (let symbol of Object.getOwnPropertySymbols(next)) {
521-
var n = next[symbol];
502+
for (let symbol of Object.getOwnPropertySymbols(next)) {
503+
var n = next[symbol];
522504

523-
if (symbol.description === ATTACHMENT_KEY && (!prev || n !== prev[symbol])) {
524-
if (effects[symbol]) destroy_effect(effects[symbol]);
525-
effects[symbol] = branch(() => attach(element, () => n));
505+
if (symbol.description === ATTACHMENT_KEY && (!prev || n !== prev[symbol])) {
506+
if (effects[symbol]) destroy_effect(effects[symbol]);
507+
effects[symbol] = branch(() => attach(element, () => n));
508+
}
509+
510+
current[symbol] = n;
526511
}
527512

528-
current[symbol] = n;
513+
prev = current;
514+
});
515+
516+
if (is_select) {
517+
init_select(
518+
/** @type {HTMLSelectElement} */ (element),
519+
() => /** @type {Record<string | symbol, any>} */ (prev).value
520+
);
529521
}
530522

531-
prev = current;
523+
inited = true;
532524
});
533-
534-
if (is_select) {
535-
init_select(
536-
/** @type {HTMLSelectElement} */ (element),
537-
() => /** @type {Record<string | symbol, any>} */ (prev).value
538-
);
539-
}
540-
541-
inited = true;
542525
}
543526

544527
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/** @import { Effect, Value } from '#client' */
2+
3+
import { DESTROYED } from '#client/constants';
4+
import { is_runes } from '../context.js';
5+
import { capture, get_pending_boundary } from '../dom/blocks/boundary.js';
6+
import { invoke_error_boundary } from '../error-handling.js';
7+
import { active_effect } from '../runtime.js';
8+
import { current_batch } from './batch.js';
9+
import { async_derived, derived, derived_safe_equal } from './deriveds.js';
10+
11+
/**
12+
*
13+
* @param {Array<() => any>} sync
14+
* @param {Array<() => Promise<any>>} async
15+
* @param {(values: Value[]) => any} fn
16+
*/
17+
export function flatten(sync, async, fn) {
18+
const d = is_runes() ? derived : derived_safe_equal;
19+
20+
if (async.length > 0) {
21+
var batch = current_batch;
22+
var parent = /** @type {Effect} */ (active_effect);
23+
24+
var restore = capture();
25+
26+
var boundary = get_pending_boundary();
27+
28+
Promise.all(async.map((expression) => async_derived(expression)))
29+
.then((result) => {
30+
if ((parent.f & DESTROYED) !== 0) return;
31+
32+
batch?.restore();
33+
34+
restore();
35+
36+
try {
37+
fn([...sync.map(d), ...result]);
38+
} catch (error) {
39+
invoke_error_boundary(error, parent);
40+
}
41+
42+
batch?.flush();
43+
})
44+
.catch((error) => {
45+
boundary.error(error);
46+
});
47+
} else {
48+
fn(sync.map(d));
49+
}
50+
}

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager, Value } from '#client' */
1+
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
22
import {
33
check_dirtiness,
44
active_effect,
@@ -38,11 +38,9 @@ import * as e from '../errors.js';
3838
import { DEV } from 'esm-env';
3939
import { define_property } from '../../shared/utils.js';
4040
import { get_next_sibling } from '../dom/operations.js';
41-
import { async_derived, derived } from './deriveds.js';
42-
import { capture } from '../dom/blocks/boundary.js';
4341
import { component_context, dev_current_component_function } from '../context.js';
44-
import { Batch, current_batch } from './batch.js';
45-
import { invoke_error_boundary } from '../error-handling.js';
42+
import { Batch } from './batch.js';
43+
import { flatten } from './async.js';
4644

4745
/**
4846
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
@@ -338,43 +336,11 @@ export function render_effect(fn, flags = 0) {
338336
* @param {(...expressions: any) => void | (() => void)} fn
339337
* @param {Array<() => any>} sync
340338
* @param {Array<() => Promise<any>>} async
341-
* @param {<T>(fn: () => T) => Derived<T>} d
342339
*/
343-
export function template_effect(fn, sync = [], async = [], d = derived) {
344-
if (async.length > 0) {
345-
var batch = current_batch;
346-
var parent = /** @type {Effect} */ (active_effect);
347-
348-
var restore = capture();
349-
350-
Promise.all(async.map((expression) => async_derived(expression))).then((result) => {
351-
if ((parent.f & DESTROYED) !== 0) return;
352-
353-
// TODO probably need to do this in async.js as well
354-
batch?.restore();
355-
356-
restore();
357-
358-
try {
359-
create_template_effect(fn, [...sync.map(d), ...result]);
360-
} catch (error) {
361-
invoke_error_boundary(error, parent);
362-
}
363-
364-
batch?.flush();
365-
});
366-
} else {
367-
create_template_effect(fn, sync.map(d));
368-
}
369-
}
370-
371-
/**
372-
* @param {(...expressions: any) => void | (() => void)} fn
373-
* @param {Value[]} deriveds
374-
*/
375-
function create_template_effect(fn, deriveds) {
376-
var effect = () => fn(...deriveds.map(get));
377-
create_effect(RENDER_EFFECT, effect, true);
340+
export function template_effect(fn, sync = [], async = []) {
341+
flatten(sync, async, (values) => {
342+
create_effect(RENDER_EFFECT, () => fn(...values.map(get)), true);
343+
});
378344
}
379345

380346
/**

0 commit comments

Comments
 (0)