mirror of https://github.com/sveltejs/svelte
parent
522744b47e
commit
cfd6ff54f3
@ -0,0 +1,133 @@
|
|||||||
|
import deindent from '../../../utils/deindent';
|
||||||
|
import visit from '../visit';
|
||||||
|
import { DomGenerator } from '../index';
|
||||||
|
import Block from '../Block';
|
||||||
|
import isDomNode from './shared/isDomNode';
|
||||||
|
import { Node } from '../../../interfaces';
|
||||||
|
import { State } from '../interfaces';
|
||||||
|
|
||||||
|
export default function visitAwaitBlock(
|
||||||
|
generator: DomGenerator,
|
||||||
|
block: Block,
|
||||||
|
state: State,
|
||||||
|
node: Node,
|
||||||
|
elementStack: Node[],
|
||||||
|
componentStack: Node[]
|
||||||
|
) {
|
||||||
|
const name = node.var;
|
||||||
|
|
||||||
|
const needsAnchor = node.next ? !isDomNode(node.next, generator) : !state.parentNode || !isDomNode(node.parent, generator);
|
||||||
|
const anchor = needsAnchor
|
||||||
|
? block.getUniqueName(`${name}_anchor`)
|
||||||
|
: (node.next && node.next.var) || 'null';
|
||||||
|
|
||||||
|
const params = block.params.join(', ');
|
||||||
|
|
||||||
|
block.contextualise(node.expression);
|
||||||
|
const { snippet } = node.metadata;
|
||||||
|
|
||||||
|
if (needsAnchor) {
|
||||||
|
block.addElement(
|
||||||
|
anchor,
|
||||||
|
`@createComment()`,
|
||||||
|
`@createComment()`,
|
||||||
|
state.parentNode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const promise = block.getUniqueName(`promise`);
|
||||||
|
const resolved = block.getUniqueName(`resolved`);
|
||||||
|
const status = block.getUniqueName(`status`);
|
||||||
|
const select_block_type = block.getUniqueName(`select_block_type`);
|
||||||
|
const await_block = block.getUniqueName(`await_block`);
|
||||||
|
const await_block_type = block.getUniqueName(`await_block_type`);
|
||||||
|
const token = block.getUniqueName(`token`);
|
||||||
|
const await_token = block.getUniqueName(`await_token`);
|
||||||
|
const update = block.getUniqueName(`update`);
|
||||||
|
const handle_promise = block.getUniqueName(`handle_promise`);
|
||||||
|
const value = block.getUniqueName(`value`);
|
||||||
|
const error = block.getUniqueName(`error`);
|
||||||
|
const create_pending_block = node.pending._block.name;
|
||||||
|
const create_then_block = node.then._block.name;
|
||||||
|
const create_catch_block = node.catch._block.name;
|
||||||
|
|
||||||
|
const conditions = [];
|
||||||
|
if (node.metadata.dependencies) {
|
||||||
|
conditions.push(
|
||||||
|
`(${node.metadata.dependencies.map(dep => `'${dep}' in changed`).join(' || ')})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
conditions.push(`${promise} !== (${promise} = ${snippet})`);
|
||||||
|
|
||||||
|
block.addVariable(await_block);
|
||||||
|
block.addVariable(await_block_type);
|
||||||
|
block.addVariable(await_token);
|
||||||
|
block.addVariable(promise);
|
||||||
|
block.addVariable(resolved);
|
||||||
|
|
||||||
|
block.builders.init.addBlock(deindent`
|
||||||
|
function ${handle_promise}(${promise}, ${params}) {
|
||||||
|
var ${token} = ${await_token} = {};
|
||||||
|
|
||||||
|
if (@isPromise(${promise})) {
|
||||||
|
${promise}.then(function(${value}) {
|
||||||
|
if (${token} !== ${await_token}) return;
|
||||||
|
${await_block}.u();
|
||||||
|
${await_block}.d();
|
||||||
|
${await_block} = (${await_block_type} = ${create_then_block})(${params}, ${resolved} = ${value}, #component);
|
||||||
|
${await_block}.c();
|
||||||
|
${await_block}.m(${anchor}.parentNode, ${anchor});
|
||||||
|
}, function (${error}) {
|
||||||
|
if (${token} !== ${await_token}) return;
|
||||||
|
${await_block}.u();
|
||||||
|
${await_block}.d();
|
||||||
|
${await_block} = (${await_block_type} = ${create_catch_block})(${params}, ${resolved} = ${error}, #component);
|
||||||
|
${await_block}.c();
|
||||||
|
${await_block}.m(${anchor}.parentNode, ${anchor});
|
||||||
|
});
|
||||||
|
|
||||||
|
// if we previously had a then/catch block, destroy it
|
||||||
|
if (${await_block_type} !== ${create_pending_block}) {
|
||||||
|
if (${await_block}) ${await_block}.d();
|
||||||
|
${await_block} = (${await_block_type} = ${create_pending_block})(${params}, ${resolved} = null, #component);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (${await_block_type} !== ${create_then_block}) {
|
||||||
|
if (${await_block}) ${await_block}.d();
|
||||||
|
${await_block} = (${await_block_type} = ${create_then_block})(${params}, ${resolved} = promise, #component);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${handle_promise}(${promise} = ${snippet}, ${params});
|
||||||
|
`);
|
||||||
|
|
||||||
|
block.builders.create.addBlock(deindent`
|
||||||
|
${await_block}.c();
|
||||||
|
`);
|
||||||
|
|
||||||
|
block.builders.claim.addBlock(deindent`
|
||||||
|
${await_block}.l(${state.parentNodes});
|
||||||
|
`);
|
||||||
|
|
||||||
|
const targetNode = state.parentNode || '#target';
|
||||||
|
const anchorNode = state.parentNode ? 'null' : 'anchor';
|
||||||
|
|
||||||
|
block.builders.mount.addBlock(deindent`
|
||||||
|
${await_block}.m(${targetNode}, ${anchor});
|
||||||
|
`);
|
||||||
|
|
||||||
|
block.builders.destroy.addBlock(deindent`
|
||||||
|
${await_token} = null;
|
||||||
|
${await_block}.d();
|
||||||
|
`);
|
||||||
|
|
||||||
|
[node.pending, node.then, node.catch].forEach(status => {
|
||||||
|
status.children.forEach(child => {
|
||||||
|
visit(generator, status._block, status._state, child, elementStack, componentStack);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
let fulfil;
|
||||||
|
|
||||||
|
let thePromise = new Promise(f => {
|
||||||
|
fulfil = f;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
solo: true,
|
||||||
|
|
||||||
|
data: {
|
||||||
|
thePromise
|
||||||
|
},
|
||||||
|
|
||||||
|
html: `
|
||||||
|
<p>loading...</p>
|
||||||
|
`,
|
||||||
|
|
||||||
|
async test(assert, component, target) {
|
||||||
|
fulfil(42);
|
||||||
|
await thePromise;
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>the value is 42</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
let reject;
|
||||||
|
|
||||||
|
thePromise = new Promise((f, r) => {
|
||||||
|
reject = r;
|
||||||
|
});
|
||||||
|
|
||||||
|
component.set({
|
||||||
|
thePromise
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>loading...</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
reject(new Error('something broke'));
|
||||||
|
await thePromise;
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>oh no! something broke</p>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
{{#await thePromise}}
|
||||||
|
<p>loading...</p>
|
||||||
|
{{then theValue}}
|
||||||
|
<p>the value is {{theValue}}</p>
|
||||||
|
{{catch theError}}
|
||||||
|
<p>oh no! {{theError.message}}</p>
|
||||||
|
{{/await}}
|
Loading…
Reference in new issue