fix: disable promise callback when {#await} is destroyed (#13241)

* fix 13236 : disable promise callback when {#await} is destroyed

* lint

* test-case

* format/lint

* test rewritten
pull/13255/head
adiGuba 1 year ago committed by GitHub
parent 47918328d7
commit 501f415190
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -40,7 +40,7 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) {
/** @type {any} */
var component_function = DEV ? component_context?.function : null;
/** @type {V | Promise<V>} */
/** @type {V | Promise<V> | null} */
var input;
/** @type {Effect | null} */
@ -146,9 +146,8 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) {
update(THEN, false);
}
// Inert effects are proactively detached from the effect tree. Returning a noop
// teardown function is an easy way to ensure that this is not discarded
return noop;
// Set the input to null, in order to disable the promise callbacks
return () => (input = null);
});
if (hydrating) {

@ -0,0 +1,94 @@
import { test } from '../../test';
/**
* Polyfill for Promise.withResolver()
* @returns { {promise: Promise<string>, resolve: (value: any)=>void, reject: (reason?: any) => void} }
*/
function promiseWithResolver() {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
// @ts-ignore
return { promise, resolve, reject };
}
export default test({
async test({ component, assert, logs }) {
{
// Set a promise on the component
const { promise, resolve } = promiseWithResolver();
component.promise = promise;
// wait for rendering
await Promise.resolve();
// resolve promise
resolve('ok');
// And wait the end of the promise
await promise;
// {#await} and {:then} block must be rendered
assert.deepEqual(logs, ['await', 'then:ok']);
}
// clear logs
logs.length = 0;
{
// Set a promise on the component
const { promise, reject } = promiseWithResolver();
component.promise = promise;
// wait for rendering
await Promise.resolve();
// reject promise
reject('error');
// And wait the end of the promise
await promise.catch((ignore) => {});
// {#await} and {:catch} block must be rendered
assert.deepEqual(logs, ['await', 'catch:error']);
}
// clear logs
logs.length = 0;
{
// Set a promise on the component
const { promise, resolve } = promiseWithResolver();
component.promise = promise;
// wait for rendering
await Promise.resolve();
// remove the promise
component.promise = null;
await Promise.resolve();
// resolve promise
resolve('ok');
// And wait the end of the promise
await promise;
// Only {#await} block must be rendered
assert.deepEqual(logs, ['await']);
}
// clear logs
logs.length = 0;
{
// Set a promise on the component
const { promise, reject } = promiseWithResolver();
component.promise = promise;
// wait for rendering
await Promise.resolve();
// remove the promise
component.promise = null;
await Promise.resolve();
// reject promise
reject('error');
// And wait the end of the promise
await promise.catch((ignore) => {});
// Only {#await} block must be rendered
assert.deepEqual(logs, ['await']);
}
}
});

@ -0,0 +1,16 @@
<script>
let { promise } = $props();
</script>
{#if promise}
{#await promise}
{console.log("await")}
{:then r}
{console.log("then:"+r)}
{:catch err}
{console.log("catch:"+err)}
{/await}
{/if}
Loading…
Cancel
Save