aaa
Rich Harris 8 months ago
parent b0a08f5034
commit 1320130862

@ -266,7 +266,7 @@ export function analyze_module(ast, options) {
immutable: true,
tracing: analysis.tracing,
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(),
is_async: false,
async_deriveds: new Set(),
blocking_awaits: new Set()
suspenders: new Set()
};
if (!runes) {

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

@ -219,6 +219,9 @@ export function CallExpression(node, context) {
if (expression.is_async) {
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') {
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
*/
export function AwaitExpression(node, context) {
if (!context.state.analysis.runes) {
const suspend = context.state.analysis.suspenders.has(node);
if (!suspend) {
return context.next();
}
const block = context.state.analysis.blocking_awaits.has(node);
return b.call(
b.member(
b.await(
b.call(
'$.preserve_context',
node.argument && /** @type {Expression} */ (context.visit(node.argument)),
block && b.true
'$.suspend',
node.argument && /** @type {Expression} */ (context.visit(node.argument))
)
),
'read'
'exit'
)
);
}

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

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

@ -129,7 +129,7 @@ export {
update_store,
mark_store_binding
} 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 {
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 { get_stack } from '../dev/tracing.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
@ -103,7 +103,9 @@ export async function async_derived(fn) {
// TODO what happens when the promise rejects?
});
(await preserve_context(promise)).read();
// wait for the initial promise
(await suspend(promise)).exit();
return () => get(value);
}

Loading…
Cancel
Save