mirror of
https://github.com/sveltejs/svelte.git
synced 2024-12-01 17:30:59 +01:00
handle await block promises in a shared helper
This commit is contained in:
parent
6aa254ab0b
commit
46c6b4bfe3
@ -77,6 +77,7 @@ export default class AwaitBlock extends Node {
|
||||
|
||||
const { snippet } = this.expression;
|
||||
|
||||
const info = block.getUniqueName(`info`);
|
||||
const promise = block.getUniqueName(`promise`);
|
||||
const resolved = block.getUniqueName(`resolved`);
|
||||
const await_block = block.getUniqueName(`await_block`);
|
||||
@ -100,71 +101,38 @@ export default class AwaitBlock extends Node {
|
||||
|
||||
block.maintainContext = true;
|
||||
|
||||
const infoProps = [
|
||||
block.alias('component') === 'component' ? 'component' : `component: #component`,
|
||||
'ctx',
|
||||
'current: null',
|
||||
create_pending_block && `pending: ${create_pending_block}`,
|
||||
create_then_block && `then: ${create_then_block}`,
|
||||
create_catch_block && `catch: ${create_catch_block}`,
|
||||
create_then_block && `value: '${this.value}'`,
|
||||
create_catch_block && `error: '${this.error}'`
|
||||
].filter(Boolean);
|
||||
|
||||
block.builders.init.addBlock(deindent`
|
||||
let ${info} = {
|
||||
${infoProps.join(',\n')}
|
||||
};
|
||||
`);
|
||||
|
||||
// the `#component.root.set({})` below is just a cheap way to flush
|
||||
// any oncreate handlers. We could have a dedicated `flush()` method
|
||||
// but it's probably not worth it
|
||||
|
||||
block.builders.init.addBlock(deindent`
|
||||
function ${replace_await_block}(${token}, type, ctx) {
|
||||
if (${token} !== ${await_token}) return;
|
||||
|
||||
var ${old_block} = ${await_block};
|
||||
${await_block} = type && (${await_block_type} = type)(#component, ctx);
|
||||
|
||||
if (${old_block}) {
|
||||
${old_block}.u();
|
||||
${old_block}.d();
|
||||
${await_block}.c();
|
||||
${await_block}.m(${updateMountNode}, ${anchor});
|
||||
|
||||
#component.root.set({});
|
||||
}
|
||||
}
|
||||
|
||||
function ${handle_promise}(${promise}) {
|
||||
var ${token} = ${await_token} = {};
|
||||
|
||||
if (@isPromise(${promise})) {
|
||||
${promise}.then(function(${value}) {
|
||||
${this.value ? deindent`
|
||||
${resolved} = { ${this.value}: ${value} };
|
||||
${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, ctx), ${resolved}));
|
||||
` : deindent`
|
||||
${replace_await_block}(${token}, null, null);
|
||||
`}
|
||||
}, function (${error}) {
|
||||
${this.error ? deindent`
|
||||
${resolved} = { ${this.error}: ${error} };
|
||||
${replace_await_block}(${token}, ${create_catch_block}, @assign(@assign({}, ctx), ${resolved}));
|
||||
` : deindent`
|
||||
${replace_await_block}(${token}, null, null);
|
||||
`}
|
||||
});
|
||||
|
||||
// if we previously had a then/catch block, destroy it
|
||||
if (${await_block_type} !== ${create_pending_block}) {
|
||||
${replace_await_block}(${token}, ${create_pending_block}, ctx);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
${resolved} = { ${this.value}: ${promise} };
|
||||
if (${await_block_type} !== ${create_then_block}) {
|
||||
${replace_await_block}(${token}, ${create_then_block}, @assign(@assign({}, ctx), ${resolved}));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${handle_promise}(${promise} = ${snippet});
|
||||
@handlePromise(${promise} = ${snippet}, ${info});
|
||||
`);
|
||||
|
||||
block.builders.create.addBlock(deindent`
|
||||
${await_block}.c();
|
||||
${info}.block.c();
|
||||
`);
|
||||
|
||||
if (parentNodes) {
|
||||
block.builders.claim.addBlock(deindent`
|
||||
${await_block}.l(${parentNodes});
|
||||
${info}.block.l(${parentNodes});
|
||||
`);
|
||||
}
|
||||
|
||||
@ -172,7 +140,8 @@ export default class AwaitBlock extends Node {
|
||||
const anchorNode = parentNode ? 'null' : 'anchor';
|
||||
|
||||
block.builders.mount.addBlock(deindent`
|
||||
${await_block}.m(${initialMountNode}, ${anchorNode});
|
||||
${info}.block.m(${initialMountNode}, ${info}.anchor = ${anchorNode});
|
||||
${info}.mount = () => ${updateMountNode};
|
||||
`);
|
||||
|
||||
const conditions = [];
|
||||
@ -184,7 +153,11 @@ export default class AwaitBlock extends Node {
|
||||
|
||||
conditions.push(
|
||||
`${promise} !== (${promise} = ${snippet})`,
|
||||
`${handle_promise}(${promise}, ctx)`
|
||||
`@handlePromise(${promise}, ${info})`
|
||||
);
|
||||
|
||||
block.builders.update.addLine(
|
||||
`${info}.ctx = ctx`
|
||||
);
|
||||
|
||||
if (this.pending.block.hasUpdateMethod) {
|
||||
@ -192,25 +165,25 @@ export default class AwaitBlock extends Node {
|
||||
if (${conditions.join(' && ')}) {
|
||||
// nothing
|
||||
} else {
|
||||
${await_block}.p(changed, @assign(@assign({}, ctx), ${resolved}));
|
||||
${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved));
|
||||
}
|
||||
`);
|
||||
} else {
|
||||
block.builders.update.addBlock(deindent`
|
||||
if (${conditions.join(' && ')}) {
|
||||
${await_block}.c();
|
||||
${await_block}.m(${anchor}.parentNode, ${anchor});
|
||||
${info}.block.c();
|
||||
${info}.block.m(${anchor}.parentNode, ${anchor});
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
block.builders.unmount.addBlock(deindent`
|
||||
${await_block}.u();
|
||||
${info}.block.u();
|
||||
`);
|
||||
|
||||
block.builders.destroy.addBlock(deindent`
|
||||
${await_token} = null;
|
||||
${await_block}.d();
|
||||
${info}.block.d();
|
||||
`);
|
||||
|
||||
[this.pending, this.then, this.catch].forEach(status => {
|
||||
|
55
src/shared/await-block.js
Normal file
55
src/shared/await-block.js
Normal file
@ -0,0 +1,55 @@
|
||||
import { assign, isPromise } from './utils.js';
|
||||
|
||||
export function handlePromise(promise, info, mount, anchor) {
|
||||
var token = info.token = {};
|
||||
|
||||
function update(type) {
|
||||
if (info.token !== token) return;
|
||||
|
||||
const child_ctx = assign(assign({}, info.ctx), info.resolved);
|
||||
const block = type && (info.current = type)(info.component, child_ctx);
|
||||
|
||||
if (info.block) {
|
||||
info.block.u();
|
||||
info.block.d();
|
||||
block.c();
|
||||
block.m(info.mount(), info.anchor);
|
||||
|
||||
info.component.root.set({});
|
||||
}
|
||||
|
||||
info.block = block;
|
||||
}
|
||||
|
||||
if (isPromise(promise)) {
|
||||
promise.then(value => {
|
||||
if (info.value) {
|
||||
info.resolved = { [info.value]: value };
|
||||
update(info.then);
|
||||
} else {
|
||||
info.resolved = null;
|
||||
update(null);
|
||||
}
|
||||
}, error => {
|
||||
if (info.error) {
|
||||
info.resolved = { [info.error]: error };
|
||||
update(info.catch);
|
||||
} else {
|
||||
info.resolved = null;
|
||||
update(null);
|
||||
}
|
||||
});
|
||||
|
||||
// if we previously had a then/catch block, destroy it
|
||||
if (info.current !== info.pending) {
|
||||
update(info.pending);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
info.resolved = { [info.value]: promise };
|
||||
if (info.current !== info.then) {
|
||||
update(info.then);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { assign } from './utils.js';
|
||||
import { noop } from './utils.js';
|
||||
export * from './await-block.js';
|
||||
export * from './dom.js';
|
||||
export * from './keyed-each.js';
|
||||
export * from './spread.js';
|
||||
@ -136,10 +137,6 @@ export function _unmount() {
|
||||
if (this._fragment) this._fragment.u();
|
||||
}
|
||||
|
||||
export function isPromise(value) {
|
||||
return value && typeof value.then === 'function';
|
||||
}
|
||||
|
||||
export var PENDING = {};
|
||||
export var SUCCESS = {};
|
||||
export var FAILURE = {};
|
||||
|
@ -9,3 +9,7 @@ export function assignTrue(tar, src) {
|
||||
for (var k in src) tar[k] = 1;
|
||||
return tar;
|
||||
}
|
||||
|
||||
export function isPromise(value) {
|
||||
return value && typeof value.then === 'function';
|
||||
}
|
Loading…
Reference in New Issue
Block a user