aaa
Rich Harris 8 months ago
parent b0a08f5034
commit 1320130862

@ -266,7 +266,7 @@ export function analyze_module(ast, options) {
immutable: true, immutable: true,
tracing: analysis.tracing, tracing: analysis.tracing,
async_deriveds: new Set(), async_deriveds: new Set(),
blocking_awaits: new Set() suspenders: new Set()
}; };
} }
@ -455,7 +455,7 @@ export function analyze_component(root, source, options) {
snippets: new Set(), snippets: new Set(),
is_async: false, is_async: false,
async_deriveds: new Set(), async_deriveds: new Set(),
blocking_awaits: new Set() suspenders: new Set()
}; };
if (!runes) { if (!runes) {

@ -14,7 +14,7 @@ export function AwaitExpression(node, context) {
throw new Error('TODO runes mode only'); throw new Error('TODO runes mode only');
} }
context.state.analysis.blocking_awaits.add(node); context.state.analysis.suspenders.add(node);
} }
if (context.state.expression) { if (context.state.expression) {

@ -219,6 +219,9 @@ export function CallExpression(node, context) {
if (expression.is_async) { if (expression.is_async) {
context.state.analysis.async_deriveds.add(node); context.state.analysis.async_deriveds.add(node);
context.state.analysis.is_async ||=
context.state.ast_type === 'instance' && context.state.function_depth === 1;
} }
} else if (rune === '$inspect') { } else if (rune === '$inspect') {
context.next({ ...context.state, function_depth: context.state.function_depth + 1 }); context.next({ ...context.state, function_depth: context.state.function_depth + 1 });

@ -7,22 +7,21 @@ import * as b from '../../../../utils/builders.js';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function AwaitExpression(node, context) { export function AwaitExpression(node, context) {
if (!context.state.analysis.runes) { const suspend = context.state.analysis.suspenders.has(node);
if (!suspend) {
return context.next(); return context.next();
} }
const block = context.state.analysis.blocking_awaits.has(node);
return b.call( return b.call(
b.member( b.member(
b.await( b.await(
b.call( b.call(
'$.preserve_context', '$.suspend',
node.argument && /** @type {Expression} */ (context.visit(node.argument)), node.argument && /** @type {Expression} */ (context.visit(node.argument))
block && b.true
) )
), ),
'read' 'exit'
) )
); );
} }

@ -43,7 +43,7 @@ export interface Analysis {
async_deriveds: Set<CallExpression>; async_deriveds: Set<CallExpression>;
/** A set of `await` expressions that should trigger suspense */ /** A set of `await` expressions that should trigger suspense */
blocking_awaits: Set<AwaitExpression>; suspenders: Set<AwaitExpression>;
} }
export interface ComponentAnalysis extends Analysis { export interface ComponentAnalysis extends Analysis {

@ -247,15 +247,14 @@ export function trigger_async_boundary(effect, trigger) {
/** /**
* @template T * @template T
* @param {Promise<T>} promise * @param {Promise<T>} promise
* @param {boolean} block * @returns {Promise<{ exit: () => T }>}
* @returns {Promise<{ read: () => T }>}
*/ */
export function preserve_context(promise, block = false) { export async function suspend(promise) {
var previous_effect = active_effect; var previous_effect = active_effect;
var previous_reaction = active_reaction; var previous_reaction = active_reaction;
var previous_component_context = component_context; var previous_component_context = component_context;
let boundary = block ? active_effect : null; let boundary = active_effect;
while (boundary !== null) { while (boundary !== null) {
if ((boundary.f & BOUNDARY_EFFECT) !== 0) { if ((boundary.f & BOUNDARY_EFFECT) !== 0) {
break; break;
@ -264,16 +263,17 @@ export function preserve_context(promise, block = false) {
boundary = boundary.parent; boundary = boundary.parent;
} }
if (block && boundary === null) { if (boundary === null) {
throw new Error('cannot suspend outside a boundary'); throw new Error('cannot suspend outside a boundary');
} }
// @ts-ignore // @ts-ignore
boundary?.fn(ASYNC_INCREMENT); boundary?.fn(ASYNC_INCREMENT);
return promise.then((value) => { const value = await promise;
return { return {
read() { exit() {
set_active_effect(previous_effect); set_active_effect(previous_effect);
set_active_reaction(previous_reaction); set_active_reaction(previous_reaction);
set_component_context(previous_component_context); set_component_context(previous_component_context);
@ -284,5 +284,4 @@ export function preserve_context(promise, block = false) {
return value; return value;
} }
}; };
});
} }

@ -129,7 +129,7 @@ export {
update_store, update_store,
mark_store_binding mark_store_binding
} from './reactivity/store.js'; } from './reactivity/store.js';
export { boundary, preserve_context } from './dom/blocks/boundary.js'; export { boundary, suspend } from './dom/blocks/boundary.js';
export { set_text } from './render.js'; export { set_text } from './render.js';
export { export {
get, get,

@ -27,7 +27,7 @@ import { destroy_effect, render_effect } from './effects.js';
import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js'; import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js';
import { get_stack } from '../dev/tracing.js'; import { get_stack } from '../dev/tracing.js';
import { tracing_mode_flag } from '../../flags/index.js'; import { tracing_mode_flag } from '../../flags/index.js';
import { preserve_context } from '../dom/blocks/boundary.js'; import { suspend } from '../dom/blocks/boundary.js';
/** /**
* @template V * @template V
@ -103,7 +103,9 @@ export async function async_derived(fn) {
// TODO what happens when the promise rejects? // TODO what happens when the promise rejects?
}); });
(await preserve_context(promise)).read(); // wait for the initial promise
(await suspend(promise)).exit();
return () => get(value); return () => get(value);
} }

Loading…
Cancel
Save