try adding regular `await`ed variables

parallelize-async-work
ComputerGuy 5 days ago
parent 710d6a6282
commit cd8969a905

@ -184,7 +184,7 @@ export function client_component(analysis, options) {
after_update: /** @type {any} */ (null),
template: /** @type {any} */ (null),
memoizer: /** @type {any} */ (null),
parallelized_derived_chunks: [],
parallelized_chunks: [],
current_parallelized_chunk: null
};

@ -9,7 +9,7 @@ import type {
VariableDeclaration,
Pattern
} from 'estree';
import type { AST, Namespace, ValidatedCompileOptions } from '#compiler';
import type { AST, Binding, Namespace, ValidatedCompileOptions } from '#compiler';
import type { TransformState } from '../types.js';
import type { ComponentAnalysis } from '../../types.js';
import type { Template } from './transform-template/template.js';
@ -83,7 +83,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly instance_level_snippets: VariableDeclaration[];
/** Snippets hoisted to the module */
readonly module_level_snippets: VariableDeclaration[];
readonly parallelized_derived_chunks: ParallelizedChunk[];
/** async deriveds and certain awaited variables are chunked so they can be parallelized via `Promise.all` */
readonly parallelized_chunks: ParallelizedChunk[];
current_parallelized_chunk: ParallelizedChunk | null;
}
@ -95,6 +96,7 @@ export interface ParallelizedChunk {
kind: VariableDeclaration['kind'];
/** index in instance body */
position: number;
bindings: Binding[];
}
export type Context = import('zimmerframe').Context<AST.SvelteNode, ClientTransformState>;

@ -33,9 +33,10 @@ export function is_state_source(binding, analysis) {
* @param {Expression} expression
* @param {Scope} scope
* @param {Analysis | ComponentAnalysis} analysis
* @param {Binding[]} bindings bindings currently being parallelized (and cannot be accessed)
* @returns {boolean}
*/
export function can_be_parallelized(expression, scope, analysis) {
export function can_be_parallelized(expression, scope, analysis, bindings) {
let has_closures = false;
/** @type {Set<string>} */
const references = new Set();
@ -70,6 +71,10 @@ export function can_be_parallelized(expression, scope, analysis) {
return false;
}
if (bindings.includes(binding)) {
return false;
}
if (binding.kind === 'derived') {
const init = /** @type {CallExpression} */ (binding.initial);
if (analysis.async_deriveds.has(init)) {

@ -141,7 +141,7 @@ export function Program(node, context) {
const body = [];
for (let i = 0; i < node.body.length; i++) {
const transformed = /** @type {Program['body'][number]} */ (context.visit(node.body[i]));
const chunk = context.state.parallelized_derived_chunks?.at(-1);
const chunk = context.state.parallelized_chunks?.at(-1);
body.push(transformed);
if (chunk && chunk.position === i) {
if (chunk.declarators.length === 1) {

@ -45,6 +45,52 @@ export function VariableDeclaration(node, context) {
continue;
}
if (
init.type === 'AwaitExpression' &&
context.state.analysis.instance?.scope === context.state.scope
) {
const parallelize = can_be_parallelized(
init.argument,
context.state.scope,
context.state.analysis,
context.state.current_parallelized_chunk?.bindings ?? []
);
if (parallelize) {
const bindings = context.state.scope.get_bindings(declarator);
const visited = /** @type {VariableDeclarator} */ (
context.visit({
...declarator,
init: init.argument
})
);
const declarators = [
{
id: visited.id,
init: /** @type {Expression} */ (visited.init)
}
];
if (
context.state.current_parallelized_chunk &&
context.state.current_parallelized_chunk.kind === node.kind
) {
context.state.current_parallelized_chunk.declarators.push(...declarators);
context.state.current_parallelized_chunk.bindings.push(...bindings);
context.state.current_parallelized_chunk.position = /** @type {Program} */ (
context.path.at(-1)
).body.indexOf(node);
} else {
const chunk = {
kind: node.kind,
declarators,
position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node),
bindings
};
context.state.current_parallelized_chunk = chunk;
context.state.parallelized_chunks.push(chunk);
}
continue;
}
}
declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
continue;
}
@ -215,11 +261,18 @@ export function VariableDeclaration(node, context) {
// TODO make it work without this
declarator.id.type === 'Identifier'
) {
parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis);
parallelize = can_be_parallelized(
value,
context.state.scope,
context.state.analysis,
context.state.current_parallelized_chunk?.bindings ?? []
);
}
/** @type {VariableDeclarator[]} */
const derived_declarators = [];
/** @type {Binding[]} */
const bindings = [];
if (declarator.id.type === 'Identifier') {
let expression = /** @type {Expression} */ (
@ -239,15 +292,13 @@ export function VariableDeclaration(node, context) {
if (!parallelize) call = b.call(b.await(b.call('$.save', call)));
if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name));
bindings.push(/** @type {Binding} */ (context.state.scope.get(declarator.id.name)));
derived_declarators.push(b.declarator(declarator.id, call));
} else {
if (rune === '$derived') expression = b.thunk(expression);
let call = b.call('$.derived', expression);
if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name));
derived_declarators.push(b.declarator(declarator.id, call));
}
} else {
const init = /** @type {CallExpression} */ (declarator.init);
@ -273,17 +324,13 @@ export function VariableDeclaration(node, context) {
b.thunk(expression, true),
location ? b.literal(location) : undefined
);
if (!parallelize) {
call = b.call(b.await(b.call('$.save', call)));
}
call = b.call(b.await(b.call('$.save', call)));
}
if (dev) {
const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`;
call = b.call('$.tag', call, b.literal(label));
}
derived_declarators.push(b.declarator(id, call));
}
const { inserts, paths } = extract_paths(declarator.id, rhs);
@ -299,8 +346,6 @@ export function VariableDeclaration(node, context) {
const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`;
call = b.call('$.tag', call, b.literal(label));
}
derived_declarators.push(b.declarator(id, call));
}
for (const path of paths) {
@ -327,19 +372,22 @@ export function VariableDeclaration(node, context) {
}));
if (
context.state.current_parallelized_chunk &&
context.state.current_parallelized_chunk.kind === node.kind &&
context.state.current_parallelized_chunk.position ===
/** @type {Program} */ (context.path.at(-1)).body.indexOf(node)
context.state.current_parallelized_chunk.kind === node.kind
) {
context.state.current_parallelized_chunk.declarators.push(...declarators);
context.state.current_parallelized_chunk.bindings.push(...bindings);
context.state.current_parallelized_chunk.position = /** @type {Program} */ (
context.path.at(-1)
).body.indexOf(node);
} else {
const chunk = {
kind: node.kind,
declarators,
position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node)
position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node),
bindings
};
context.state.current_parallelized_chunk = chunk;
context.state.parallelized_derived_chunks.push(chunk);
context.state.parallelized_chunks.push(chunk);
}
}

Loading…
Cancel
Save