Skip to content

Commit

Permalink
call on_destroy if unmounted called immediately before on_mount
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed Sep 12, 2022
1 parent 7331c06 commit 2613922
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 22 deletions.
24 changes: 5 additions & 19 deletions src/runtime/internal/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,8 @@ import { current_component, set_current_component } from './lifecycle';
import { blank_object, is_empty, is_function, run, run_all, noop } from './utils';
import { children, detach, start_hydrating, end_hydrating } from './dom';
import { transition_in } from './transitions';
import { Fragment } from './types';

/**
* INTERNAL, DO NOT USE. Code may change at any time.
*/
export interface Fragment {
key: string | null;
first: null;
/* create */ c: () => void;
/* claim */ l: (nodes: any) => void;
/* hydrate */ h: () => void;
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* update */ p: (ctx: any, dirty: any) => void;
/* measure */ r: () => void;
/* fix */ f: () => void;
/* animate */ a: () => void;
/* intro */ i: (local: any) => void;
/* outro */ o: (local: any) => void;
/* destroy */ d: (detaching: 0 | 1) => void;
}
interface T$$ {
dirty: number[];
ctx: null | any;
Expand Down Expand Up @@ -67,7 +50,10 @@ export function mount_component(component, target, anchor, customElement) {
add_render_callback(() => {

const new_on_destroy = on_mount.map(run).filter(is_function);
if (on_destroy) {
// if the component was destroyed immediately
// it will update the `$$.on_destroy` reference to `null`.
// the destructured on_destroy may still reference to the old array
if (component.$$.on_destroy) {
on_destroy.push(...new_on_destroy);
} else {
// Edge case - component was destroyed immediately,
Expand Down
29 changes: 27 additions & 2 deletions src/runtime/internal/await_block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,36 @@ import { is_promise } from './utils';
import { check_outros, group_outros, transition_in, transition_out } from './transitions';
import { flush } from './scheduler';
import { get_current_component, set_current_component } from './lifecycle';
import { Fragment, FragmentFactory } from './types';

interface PromiseInfo<T> {
ctx: null | any;
// unique object instance as a key to compare different promises
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(promise, info) {
export function handle_promise<T>(promise: Promise<T>, info: PromiseInfo<T>) {
const token = info.token = {};

function update(type, index, key?, value?) {
function update(type: FragmentFactory, index: 0 | 1 | 2, key?: number, value?) {
if (info.token !== token) return;

info.resolved = value;
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/internal/transitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { create_rule, delete_rule } from './style_manager';
import { custom_event } from './dom';
import { add_render_callback } from './scheduler';
import { TransitionConfig } from '../transition';
import { Fragment } from './Component';
import { Fragment } from './types';

let promise: Promise<void> | null;
type INTRO = 1;
Expand Down
20 changes: 20 additions & 0 deletions src/runtime/internal/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* INTERNAL, DO NOT USE. Code may change at any time.
*/
export interface Fragment {
key: string | null;
first: null;
/* create */ c: () => void;
/* claim */ l: (nodes: any) => void;
/* hydrate */ h: () => void;
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* update */ p: (ctx: any, dirty: any) => void;
/* measure */ r: () => void;
/* fix */ f: () => void;
/* animate */ a: () => void;
/* intro */ i: (local: any) => void;
/* outro */ o: (local: any) => void;
/* destroy */ d: (detaching: 0 | 1) => void;
}

export type FragmentFactory = (ctx: any) => Fragment;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
import { onMount } from 'svelte';
export let logs;
export let state;
onMount(() => {
logs.push(`mount ${state}`);
return () => {
logs.push(`unmount ${state}`);
};
});
</script>

{state}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
html: 'Loading...',
async test({ assert, component, target, window }) {
const button = target.querySelector('button');

await component.test();

assert.htmlEqual(target.innerHTML, '1');
assert.deepEqual(component.logs, ['mount 0', 'unmount 0', 'mount 1']);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script>
import { tick } from 'svelte';
import Component from './Component.svelte';
let promise;
let resolve;
let value = 0;
export let logs = [];
async function new_promise() {
promise = new Promise(r => {
resolve = r;
});
}
async function resolve_promise() {
await Promise.resolve();
resolve(value++);
}
export async function test() {
resolve_promise();
await Promise.resolve();
new_promise();
resolve_promise();
return tick();
}
new_promise();
</script>

{#await promise}
Loading...
{:then state}
<Component {state} {logs} />
{/await}

0 comments on commit 2613922

Please sign in to comment.