await blocks

pull/1367/head
Rich Harris 7 years ago
parent b843e82990
commit 6aef709385

@ -6,16 +6,31 @@ import PendingBlock from './PendingBlock';
import ThenBlock from './ThenBlock'; import ThenBlock from './ThenBlock';
import CatchBlock from './CatchBlock'; import CatchBlock from './CatchBlock';
import createDebuggingComment from '../../utils/createDebuggingComment'; import createDebuggingComment from '../../utils/createDebuggingComment';
import Expression from './shared/Expression';
export default class AwaitBlock extends Node { export default class AwaitBlock extends Node {
expression: Expression;
value: string; value: string;
error: string; error: string;
expression: Node;
pending: PendingBlock; pending: PendingBlock;
then: ThenBlock; then: ThenBlock;
catch: CatchBlock; catch: CatchBlock;
constructor(compiler, parent, scope, info) {
super(compiler, parent, scope, info);
this.expression = new Expression(compiler, this, scope, info.expression);
const deps = this.expression.dependencies;
this.value = info.value;
this.error = info.error;
this.pending = new PendingBlock(compiler, this, scope, info.pending);
this.then = new ThenBlock(compiler, this, scope.add(this.value, deps), info.then);
this.catch = new CatchBlock(compiler, this, scope.add(this.error, deps), info.catch);
}
init( init(
block: Block, block: Block,
stripWhitespace: boolean, stripWhitespace: boolean,
@ -24,7 +39,7 @@ export default class AwaitBlock extends Node {
this.cannotUseInnerHTML(); this.cannotUseInnerHTML();
this.var = block.getUniqueName('await_block'); this.var = block.getUniqueName('await_block');
block.addDependencies(this.metadata.dependencies); block.addDependencies(this.expression.dependencies);
let dynamic = false; let dynamic = false;
@ -36,8 +51,8 @@ export default class AwaitBlock extends Node {
const child = this[status]; const child = this[status];
child.block = block.child({ child.block = block.child({
comment: createDebuggingComment(child, this.generator), comment: createDebuggingComment(child, this.compiler),
name: this.generator.getUniqueName(`create_${status}_block`), name: this.compiler.getUniqueName(`create_${status}_block`),
contexts: new Map(block.contexts), contexts: new Map(block.contexts),
contextTypes: new Map(block.contextTypes) contextTypes: new Map(block.contextTypes)
}); });
@ -49,7 +64,7 @@ export default class AwaitBlock extends Node {
} }
child.initChildren(child.block, stripWhitespace, nextSibling); child.initChildren(child.block, stripWhitespace, nextSibling);
this.generator.blocks.push(child.block); this.compiler.blocks.push(child.block);
if (child.block.dependencies.size > 0) { if (child.block.dependencies.size > 0) {
dynamic = true; dynamic = true;
@ -72,8 +87,7 @@ export default class AwaitBlock extends Node {
const anchor = this.getOrCreateAnchor(block, parentNode, parentNodes); const anchor = this.getOrCreateAnchor(block, parentNode, parentNodes);
const updateMountNode = this.getUpdateMountNode(anchor); const updateMountNode = this.getUpdateMountNode(anchor);
block.contextualise(this.expression); const { snippet } = this.expression;
const { snippet } = this.metadata;
const promise = block.getUniqueName(`promise`); const promise = block.getUniqueName(`promise`);
const resolved = block.getUniqueName(`resolved`); const resolved = block.getUniqueName(`resolved`);
@ -101,11 +115,11 @@ export default class AwaitBlock extends Node {
// but it's probably not worth it // but it's probably not worth it
block.builders.init.addBlock(deindent` block.builders.init.addBlock(deindent`
function ${replace_await_block}(${token}, type, state) { function ${replace_await_block}(${token}, type, ctx) {
if (${token} !== ${await_token}) return; if (${token} !== ${await_token}) return;
var ${old_block} = ${await_block}; var ${old_block} = ${await_block};
${await_block} = type && (${await_block_type} = type)(#component, state); ${await_block} = type && (${await_block_type} = type)(#component, ctx);
if (${old_block}) { if (${old_block}) {
${old_block}.u(); ${old_block}.u();
@ -117,23 +131,23 @@ export default class AwaitBlock extends Node {
} }
} }
function ${handle_promise}(${promise}, state) { function ${handle_promise}(${promise}, ctx) {
var ${token} = ${await_token} = {}; var ${token} = ${await_token} = {};
if (@isPromise(${promise})) { if (@isPromise(${promise})) {
${promise}.then(function(${value}) { ${promise}.then(function(${value}) {
${this.then.block.context ? deindent` ${this.value ? deindent`
var state = #component.get(); var ctx = #component.get();
${resolved} = { ${this.then.block.context}: ${value} }; ${resolved} = { ${this.value}: ${value} };
${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, state), ${resolved})); ${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, ctx), ${resolved}));
` : deindent` ` : deindent`
${replace_await_block}(${token}, null, null); ${replace_await_block}(${token}, null, null);
`} `}
}, function (${error}) { }, function (${error}) {
${this.catch.block.context ? deindent` ${this.error ? deindent`
var state = #component.get(); var ctx = #component.get();
${resolved} = { ${this.catch.block.context}: ${error} }; ${resolved} = { ${this.error}: ${error} };
${replace_await_block}(${token}, ${create_catch_block}, @assign(@assign({}, state), ${resolved})); ${replace_await_block}(${token}, ${create_catch_block}, @assign(@assign({}, ctx), ${resolved}));
` : deindent` ` : deindent`
${replace_await_block}(${token}, null, null); ${replace_await_block}(${token}, null, null);
`} `}
@ -141,19 +155,19 @@ export default class AwaitBlock extends Node {
// if we previously had a then/catch block, destroy it // if we previously had a then/catch block, destroy it
if (${await_block_type} !== ${create_pending_block}) { if (${await_block_type} !== ${create_pending_block}) {
${replace_await_block}(${token}, ${create_pending_block}, state); ${replace_await_block}(${token}, ${create_pending_block}, ctx);
return true; return true;
} }
} else { } else {
${resolved} = { ${this.then.block.context}: ${promise} }; ${resolved} = { ${this.value}: ${promise} };
if (${await_block_type} !== ${create_then_block}) { if (${await_block_type} !== ${create_then_block}) {
${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, state), ${resolved})); ${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, ctx), ${resolved}));
return true; return true;
} }
} }
} }
${handle_promise}(${promise} = ${snippet}, state); ${handle_promise}(${promise} = ${snippet}, ctx);
`); `);
block.builders.create.addBlock(deindent` block.builders.create.addBlock(deindent`
@ -174,15 +188,15 @@ export default class AwaitBlock extends Node {
`); `);
const conditions = []; const conditions = [];
if (this.metadata.dependencies) { if (this.expression.dependencies.size > 0) {
conditions.push( conditions.push(
`(${this.metadata.dependencies.map(dep => `'${dep}' in changed`).join(' || ')})` `(${[...this.expression.dependencies].map(dep => `'${dep}' in changed`).join(' || ')})`
); );
} }
conditions.push( conditions.push(
`${promise} !== (${promise} = ${snippet})`, `${promise} !== (${promise} = ${snippet})`,
`${handle_promise}(${promise}, state)` `${handle_promise}(${promise}, ctx)`
); );
if (this.pending.block.hasUpdateMethod) { if (this.pending.block.hasUpdateMethod) {
@ -190,7 +204,7 @@ export default class AwaitBlock extends Node {
if (${conditions.join(' && ')}) { if (${conditions.join(' && ')}) {
// nothing // nothing
} else { } else {
${await_block}.p(changed, @assign(@assign({}, state), ${resolved})); ${await_block}.p(changed, @assign(@assign({}, ctx), ${resolved}));
} }
`); `);
} else { } else {

@ -1,7 +1,13 @@
import Node from './shared/Node'; import Node from './shared/Node';
import Block from '../dom/Block'; import Block from '../dom/Block';
import mapChildren from './shared/mapChildren';
export default class CatchBlock extends Node { export default class CatchBlock extends Node {
block: Block; block: Block;
children: Node[]; children: Node[];
constructor(compiler, parent, scope, info) {
super(compiler, parent, scope, info);
this.children = mapChildren(compiler, parent, scope, info.children);
}
} }

@ -19,6 +19,7 @@ class TemplateScope {
add(name, dependencies) { add(name, dependencies) {
this.names.add(name); this.names.add(name);
this.dependenciesForName.set(name, dependencies); this.dependenciesForName.set(name, dependencies);
return this;
} }
child() { child() {

@ -1,7 +1,13 @@
import Node from './shared/Node'; import Node from './shared/Node';
import Block from '../dom/Block'; import Block from '../dom/Block';
import mapChildren from './shared/mapChildren';
export default class PendingBlock extends Node { export default class PendingBlock extends Node {
block: Block; block: Block;
children: Node[]; children: Node[];
constructor(compiler, parent, scope, info) {
super(compiler, parent, scope, info);
this.children = mapChildren(compiler, parent, scope, info.children);
}
} }

@ -1,7 +1,13 @@
import Node from './shared/Node'; import Node from './shared/Node';
import Block from '../dom/Block'; import Block from '../dom/Block';
import mapChildren from './shared/mapChildren';
export default class ThenBlock extends Node { export default class ThenBlock extends Node {
block: Block; block: Block;
children: Node[]; children: Node[];
constructor(compiler, parent, scope, info) {
super(compiler, parent, scope, info);
this.children = mapChildren(compiler, parent, scope, info.children);
}
} }

@ -1,3 +1,4 @@
import AwaitBlock from '../AwaitBlock';
import Component from '../Component'; import Component from '../Component';
import EachBlock from '../EachBlock'; import EachBlock from '../EachBlock';
import Element from '../Element'; import Element from '../Element';
@ -11,6 +12,7 @@ import Node from './Node';
function getConstructor(type): typeof Node { function getConstructor(type): typeof Node {
switch (type) { switch (type) {
case 'AwaitBlock': return AwaitBlock;
case 'Component': return Component; case 'Component': return Component;
case 'EachBlock': return EachBlock; case 'EachBlock': return EachBlock;
case 'Element': return Element; case 'Element': return Element;

Loading…
Cancel
Save