feat: Convert src/runtime/internal/await_block.ts to JavaScript

pull/8569/head
S. Elliott Johnson 3 years ago
parent 0af3f6c83b
commit c6344f0bf4

@ -2,51 +2,28 @@ import { is_promise } from './utils';
import { check_outros, group_outros, transition_in, transition_out } from './transitions'; import { check_outros, group_outros, transition_in, transition_out } from './transitions';
import { flush } from './scheduler'; import { flush } from './scheduler';
import { get_current_component, set_current_component } from './lifecycle'; import { get_current_component, set_current_component } from './lifecycle';
import { Fragment, FragmentFactory } from './types'; /** @param {Promise<T>} promise
* @param {PromiseInfo<T>} info
interface PromiseInfo<T> { * @returns {boolean}
ctx: null | any; */
// unique object instance as a key to compare different promises export function handle_promise(promise, info) {
token: {};
hasCatch: boolean;
pending: FragmentFactory;
then: FragmentFactory;
catch: FragmentFactory;
// ctx index for resolved value and rejected error
value: number;
error: number;
// resolved value or rejected error
resolved?: T;
// the current factory function for creating the fragment
current: FragmentFactory | null;
// the current fragment
block: Fragment | null;
// tuple of the pending, then, catch fragment
blocks: [null | Fragment, null | Fragment, null | Fragment];
// DOM elements to mount and anchor on for the {#await} block
mount: () => HTMLElement;
anchor: HTMLElement;
}
export function handle_promise<T>(promise: Promise<T>, info: PromiseInfo<T>) {
const token = (info.token = {}); const token = (info.token = {});
/** @param {FragmentFactory} type
function update(type: FragmentFactory, index: 0 | 1 | 2, key?: number, value?) { * @param {0 | 1 | 2} index
if (info.token !== token) return; * @param {number} key
* @returns {void}
*/
function update(type, index, key, value) {
if (info.token !== token)
return;
info.resolved = value; info.resolved = value;
let child_ctx = info.ctx; let child_ctx = info.ctx;
if (key !== undefined) { if (key !== undefined) {
child_ctx = child_ctx.slice(); child_ctx = child_ctx.slice();
child_ctx[key] = value; child_ctx[key] = value;
} }
const block = type && (info.current = type)(child_ctx); const block = type && (info.current = type)(child_ctx);
let needs_flush = false; let needs_flush = false;
if (info.block) { if (info.block) {
if (info.blocks) { if (info.blocks) {
info.blocks.forEach((block, i) => { info.blocks.forEach((block, i) => {
@ -60,68 +37,79 @@ export function handle_promise<T>(promise: Promise<T>, info: PromiseInfo<T>) {
check_outros(); check_outros();
} }
}); });
} else { }
else {
info.block.d(1); info.block.d(1);
} }
block.c(); block.c();
transition_in(block, 1); transition_in(block, 1);
block.m(info.mount(), info.anchor); block.m(info.mount(), info.anchor);
needs_flush = true; needs_flush = true;
} }
info.block = block; info.block = block;
if (info.blocks) info.blocks[index] = block; if (info.blocks)
info.blocks[index] = block;
if (needs_flush) { if (needs_flush) {
flush(); flush();
} }
} }
if (is_promise(promise)) { if (is_promise(promise)) {
const current_component = get_current_component(); const current_component = get_current_component();
promise.then( promise.then((value) => {
(value) => {
set_current_component(current_component); set_current_component(current_component);
update(info.then, 1, info.value, value); update(info.then, 1, info.value, value);
set_current_component(null); set_current_component(null);
}, }, (error) => {
(error) => {
set_current_component(current_component); set_current_component(current_component);
update(info.catch, 2, info.error, error); update(info.catch, 2, info.error, error);
set_current_component(null); set_current_component(null);
if (!info.hasCatch) { if (!info.hasCatch) {
throw error; throw error;
} }
} });
);
// if we previously had a then/catch block, destroy it // if we previously had a then/catch block, destroy it
if (info.current !== info.pending) { if (info.current !== info.pending) {
update(info.pending, 0); update(info.pending, 0);
return true; return true;
} }
} else { }
else {
if (info.current !== info.then) { if (info.current !== info.then) {
update(info.then, 1, info.value, promise); update(info.then, 1, info.value, promise);
return true; return true;
} }
info.resolved = promise; info.resolved = promise;
} }
} }
/** @returns {void} */
export function update_await_block_branch(info, ctx, dirty) { export function update_await_block_branch(info, ctx, dirty) {
const child_ctx = ctx.slice(); const child_ctx = ctx.slice();
const { resolved } = info; const { resolved } = info;
if (info.current === info.then) { if (info.current === info.then) {
child_ctx[info.value] = resolved; child_ctx[info.value] = resolved;
} }
if (info.current === info.catch) { if (info.current === info.catch) {
child_ctx[info.error] = resolved; child_ctx[info.error] = resolved;
} }
info.block.p(child_ctx, dirty); info.block.p(child_ctx, dirty);
} }
/** @typedef {Object} PromiseInfo
* @property {null|any} ctx
* @property {{}} token
* @property {boolean} hasCatch
* @property {FragmentFactory} pending
* @property {FragmentFactory} then
* @property {FragmentFactory} catch
* @property {number} value
* @property {number} error
* @property {T} [resolved]
* @property {FragmentFactory|null} current
* @property {Fragment|null} block
* @property {[null|Fragment,null|Fragment,null|Fragment]} blocks
* @property {()=>HTMLElement} mount
* @property {HTMLElement} anchor
*/
Loading…
Cancel
Save