out-of-order-rendering
Rich Harris 2 days ago
parent 20cc1c694d
commit f4b94e57a3

@ -312,9 +312,10 @@ export function EachBlock(node, context) {
declarations.push(b.let(node.index, index)); declarations.push(b.let(node.index, index));
} }
const { has_await } = node.metadata.expression; const is_async = node.metadata.expression.is_async();
const get_collection = b.thunk(collection, has_await);
const thunk = has_await ? b.thunk(b.call('$.get', b.id('$$collection'))) : get_collection; const get_collection = b.thunk(collection, node.metadata.expression.has_await);
const thunk = is_async ? b.thunk(b.call('$.get', b.id('$$collection'))) : get_collection;
const render_args = [b.id('$$anchor'), item]; const render_args = [b.id('$$anchor'), item];
if (uses_index || collection_id) render_args.push(index); if (uses_index || collection_id) render_args.push(index);
@ -341,12 +342,13 @@ export function EachBlock(node, context) {
statements.unshift(b.stmt(b.call('$.validate_each_keys', thunk, key_function))); statements.unshift(b.stmt(b.call('$.validate_each_keys', thunk, key_function)));
} }
if (has_await) { if (is_async) {
context.state.init.push( context.state.init.push(
b.stmt( b.stmt(
b.call( b.call(
'$.async', '$.async',
context.state.node, context.state.node,
node.metadata.expression.blockers(),
b.array([get_collection]), b.array([get_collection]),
b.arrow([context.state.node, b.id('$$collection')], b.block(statements)) b.arrow([context.state.node, b.id('$$collection')], b.block(statements))
) )

@ -37,7 +37,8 @@ export function HtmlTag(node, context) {
b.call( b.call(
'$.async', '$.async',
context.state.node, context.state.node,
b.array([b.thunk(expression, true)]), node.metadata.expression.blockers(),
b.array([b.thunk(expression, node.metadata.expression.has_await)]),
b.arrow([context.state.node, b.id('$$html')], b.block([statement])) b.arrow([context.state.node, b.id('$$html')], b.block([statement]))
) )
) )

@ -11,10 +11,10 @@ import { build_expression, add_svelte_meta } from './shared/utils.js';
export function KeyBlock(node, context) { export function KeyBlock(node, context) {
context.state.template.push_comment(); context.state.template.push_comment();
const { has_await } = node.metadata.expression; const is_async = node.metadata.expression.is_async();
const expression = build_expression(context, node.expression, node.metadata.expression); const expression = build_expression(context, node.expression, node.metadata.expression);
const key = b.thunk(has_await ? b.call('$.get', b.id('$$key')) : expression); const key = b.thunk(is_async ? b.call('$.get', b.id('$$key')) : expression);
const body = /** @type {Expression} */ (context.visit(node.fragment)); const body = /** @type {Expression} */ (context.visit(node.fragment));
let statement = add_svelte_meta( let statement = add_svelte_meta(
@ -23,12 +23,13 @@ export function KeyBlock(node, context) {
'key' 'key'
); );
if (has_await) { if (is_async) {
statement = b.stmt( statement = b.stmt(
b.call( b.call(
'$.async', '$.async',
context.state.node, context.state.node,
b.array([b.thunk(expression, true)]), node.metadata.expression.blockers(),
b.array([b.thunk(expression, node.metadata.expression.has_await)]),
b.arrow([context.state.node, b.id('$$key')], b.block([statement])) b.arrow([context.state.node, b.id('$$key')], b.block([statement]))
) )
); );

@ -272,8 +272,21 @@ function transform_body(program, context) {
context.visit(b.var(s.node.id, s.node.init)) context.visit(b.var(s.node.id, s.node.init))
); );
if (visited.declarations.length === 1) {
return b.thunk(
b.assignment('=', s.node.id, visited.declarations[0].init ?? b.void0),
s.has_await
);
}
// if we have multiple declarations, it indicates destructuring
return b.thunk( return b.thunk(
b.assignment('=', s.node.id, visited.declarations[0].init ?? b.void0), b.block([
b.var(visited.declarations[0].id, visited.declarations[0].init),
...visited.declarations
.slice(1)
.map((d) => b.stmt(b.assignment('=', d.id, d.init ?? b.void0)))
]),
s.has_await s.has_await
); );
} }

@ -93,10 +93,10 @@ export function SvelteElement(node, context) {
); );
} }
const { has_await } = node.metadata.expression; const is_async = node.metadata.expression.is_async();
const expression = /** @type {Expression} */ (context.visit(node.tag)); const expression = /** @type {Expression} */ (context.visit(node.tag));
const get_tag = b.thunk(has_await ? b.call('$.get', b.id('$$tag')) : expression); const get_tag = b.thunk(is_async ? b.call('$.get', b.id('$$tag')) : expression);
/** @type {Statement[]} */ /** @type {Statement[]} */
const inner = inner_context.state.init; const inner = inner_context.state.init;
@ -139,13 +139,14 @@ export function SvelteElement(node, context) {
) )
); );
if (has_await) { if (is_async) {
context.state.init.push( context.state.init.push(
b.stmt( b.stmt(
b.call( b.call(
'$.async', '$.async',
context.state.node, context.state.node,
b.array([b.thunk(expression, true)]), node.metadata.expression.blockers(),
b.array([b.thunk(expression, node.metadata.expression.has_await)]),
b.arrow([context.state.node, b.id('$$tag')], b.block(statements)) b.arrow([context.state.node, b.id('$$tag')], b.block(statements))
) )
) )

@ -56,10 +56,8 @@ export function flatten(blockers, sync, async, fn) {
var was_hydrating = hydrating; var was_hydrating = hydrating;
Promise.all(blockers).then(() => { function run() {
restore(); Promise.all(async.map((expression) => async_derived(expression)))
const result = Promise.all(async.map((expression) => async_derived(expression)))
.then((result) => { .then((result) => {
restore(); restore();
@ -82,11 +80,22 @@ export function flatten(blockers, sync, async, fn) {
.catch((error) => { .catch((error) => {
invoke_error_boundary(error, parent); invoke_error_boundary(error, parent);
}); });
}
unset_context(); if (blockers.length > 0) {
Promise.all(blockers).then(() => {
restore();
return result; try {
}); return run();
} finally {
batch?.deactivate();
unset_context();
}
});
} else {
run();
}
} }
/** /**
@ -274,7 +283,8 @@ export async function async_body(anchor, fn) {
export function run(thunks) { export function run(thunks) {
const restore = capture(); const restore = capture();
let promise = Promise.resolve(); // let promise = Promise.resolve();
let promise = new Promise((f) => Batch.enqueue(() => f(undefined)));
var boundary = get_boundary(); var boundary = get_boundary();
var batch = /** @type {Batch} */ (current_batch); var batch = /** @type {Batch} */ (current_batch);

@ -34,7 +34,7 @@ import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js'; import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack, tag_proxy } from '../dev/tracing.js'; import { get_stack, tag_proxy } from '../dev/tracing.js';
import { component_context, is_runes } from '../context.js'; import { component_context, is_runes } from '../context.js';
import { Batch, eager_block_effects, schedule_effect } from './batch.js'; import { Batch, current_batch, eager_block_effects, schedule_effect } from './batch.js';
import { proxy } from '../proxy.js'; import { proxy } from '../proxy.js';
import { execute_derived } from './deriveds.js'; import { execute_derived } from './deriveds.js';

Loading…
Cancel
Save