experimental waterfall detection

aaa
Rich Harris 8 months ago
parent a0eaccc5ed
commit 118e28445d

@ -34,6 +34,14 @@ function add() {
} }
``` ```
### await_waterfall
```
Detected an unnecessary async waterfall
```
TODO
### binding_property_non_reactive ### binding_property_non_reactive
``` ```

@ -30,6 +30,12 @@ function add() {
} }
``` ```
## await_waterfall
> Detected an unnecessary async waterfall
TODO
## binding_property_non_reactive ## binding_property_non_reactive
> `%binding%` is binding to a non-reactive property > `%binding%` is binding to a non-reactive property

@ -23,6 +23,7 @@ import {
} from '../runtime.js'; } from '../runtime.js';
import { equals, safe_equals } from './equality.js'; import { equals, safe_equals } from './equality.js';
import * as e from '../errors.js'; import * as e from '../errors.js';
import * as w from '../warnings.js';
import { block, destroy_effect } from './effects.js'; import { block, destroy_effect } from './effects.js';
import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js'; import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js';
import { get_stack } from '../dev/tracing.js'; import { get_stack } from '../dev/tracing.js';
@ -77,6 +78,9 @@ export function derived(fn) {
return signal; return signal;
} }
// Used for waterfall detection
var async_deps = new Set();
/** /**
* @template V * @template V
* @param {() => Promise<V>} fn * @param {() => Promise<V>} fn
@ -84,16 +88,18 @@ export function derived(fn) {
*/ */
/*#__NO_SIDE_EFFECTS__*/ /*#__NO_SIDE_EFFECTS__*/
export function async_derived(fn) { export function async_derived(fn) {
let effect = /** @type {Effect | null} */ (active_effect); let parent = /** @type {Effect | null} */ (active_effect);
if (effect === null) { if (parent === null) {
throw new Error('TODO cannot create unowned async derived'); throw new Error('TODO cannot create unowned async derived');
} }
var promise = /** @type {Promise<V>} */ (/** @type {unknown} */ (undefined)); var promise = /** @type {Promise<V>} */ (/** @type {unknown} */ (undefined));
var value = source(/** @type {V} */ (undefined)); var value = source(/** @type {V} */ (undefined));
block(async () => { var current_deps = new Set(async_deps);
var effect = block(async () => {
var current = (promise = fn()); var current = (promise = fn());
var restore = capture(); var restore = capture();
@ -102,16 +108,45 @@ export function async_derived(fn) {
try { try {
var v = await promise; var v = await promise;
if ((effect.f & DESTROYED) !== 0) { // check to see if we just created an unnecessary waterfall
if (current_deps.size > 0) {
var justified = false;
if (effect.deps !== null) {
for (const dep of effect.deps) {
if (current_deps.has(dep)) {
justified = true;
break;
}
}
}
if (!justified) {
w.await_waterfall();
}
}
if ((parent.f & DESTROYED) !== 0) {
return; return;
} }
if (promise === current) { if (promise === current) {
restore(); restore();
internal_set(value, v); internal_set(value, v);
// make a note that we're updating this derived,
// so that we can detect waterfalls
async_deps.add(value);
// TODO we want to clear this after we've updated effects.
// `queue_post_micro_task` appears to run too early.
// for now, as a POC, use setTimeout
setTimeout(() => {
async_deps.delete(value);
});
} }
} catch (e) { } catch (e) {
handle_error(e, effect, null, effect.ctx); handle_error(e, parent, null, parent.ctx);
} finally { } finally {
unsuspend(); unsuspend();

@ -99,6 +99,7 @@ export function set_active_effect(effect) {
} }
// TODO remove this, once we're satisfied that we're not leaking context // TODO remove this, once we're satisfied that we're not leaking context
/* @__PURE__ */
setInterval(() => { setInterval(() => {
if (active_effect !== null || active_reaction !== null) { if (active_effect !== null || active_reaction !== null) {
debugger; debugger;

@ -18,6 +18,17 @@ export function assignment_value_stale(property, location) {
} }
} }
/**
* Detected an unnecessary async waterfall
*/
export function await_waterfall() {
if (DEV) {
console.warn(`%c[svelte] await_waterfall\n%cDetected an unnecessary async waterfall\nhttps://svelte.dev/e/await_waterfall`, bold, normal);
} else {
console.warn(`https://svelte.dev/e/await_waterfall`);
}
}
/** /**
* `%binding%` (%location%) is binding to a non-reactive property * `%binding%` (%location%) is binding to a non-reactive property
* @param {string} binding * @param {string} binding

Loading…
Cancel
Save