warn on reactivity loss

aa-coordination
Rich Harris 8 months ago
parent b4ee140632
commit 148ffd2783

@ -34,6 +34,14 @@ function add() {
}
```
### await_reactivity_loss
```
Detected reactivity loss
```
TODO
### await_waterfall
```

@ -30,6 +30,12 @@ function add() {
}
```
## await_reactivity_loss
> Detected reactivity loss
TODO
## await_waterfall
> Detected an unnecessary async waterfall

@ -1,5 +1,6 @@
/** @import { AwaitExpression, Expression } from 'estree' */
/** @import { Context } from '../types' */
import { dev } from '../../../../state.js';
import * as b from '../../../../utils/builders.js';
/**
@ -7,15 +8,19 @@ import * as b from '../../../../utils/builders.js';
* @param {Context} context
*/
export function AwaitExpression(node, context) {
const suspend = context.state.analysis.context_preserving_awaits.has(node);
if (!suspend) {
return context.next();
}
const save = context.state.analysis.context_preserving_awaits.has(node);
if (dev || save) {
return b.call(
b.await(
b.call('$.save', node.argument && /** @type {Expression} */ (context.visit(node.argument)))
b.call(
'$.save',
node.argument && /** @type {Expression} */ (context.visit(node.argument)),
!save && b.false
)
)
);
}
return context.next();
}

@ -30,6 +30,8 @@ import {
import { get_next_sibling } from '../operations.js';
import { queue_boundary_micro_task } from '../task.js';
import * as e from '../../../shared/errors.js';
import { DEV } from 'esm-env';
import { from_async_derived, set_from_async_derived } from '../../reactivity/deriveds.js';
const ASYNC_INCREMENT = Symbol();
const ASYNC_DECREMENT = Symbol();
@ -340,15 +342,23 @@ function move_effect(effect, fragment) {
}
}
export function capture() {
export function capture(track = true) {
var previous_effect = active_effect;
var previous_reaction = active_reaction;
var previous_component_context = component_context;
if (DEV && !track) {
var was_from_async_derived = from_async_derived;
}
return function restore() {
if (track) {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
set_component_context(previous_component_context);
} else if (DEV) {
set_from_async_derived(was_from_async_derived);
}
// prevent the active effect from outstaying its welcome
queue_boundary_micro_task(exit);
@ -390,10 +400,11 @@ export function suspend() {
/**
* @template T
* @param {Promise<T>} promise
* @param {boolean} [track]
* @returns {Promise<() => T>}
*/
export async function save(promise) {
var restore = capture();
export async function save(promise, track = true) {
var restore = capture(track);
var value = await promise;
return () => {

@ -29,6 +29,14 @@ import { tracing_mode_flag } from '../../flags/index.js';
import { capture, suspend } from '../dom/blocks/boundary.js';
import { component_context } from '../context.js';
/** @type {Effect | null} */
export let from_async_derived = null;
/** @param {Effect | null} v */
export function set_from_async_derived(v) {
from_async_derived = v;
}
/**
* @template V
* @param {() => V} fn
@ -88,8 +96,11 @@ export function async_derived(fn) {
var promise = /** @type {Promise<V>} */ (/** @type {unknown} */ (undefined));
var value = source(/** @type {V} */ (undefined));
// TODO this isn't a block
block(async () => {
if (DEV) from_async_derived = active_effect;
var current = (promise = fn());
if (DEV) from_async_derived = null;
var restore = capture();
var unsuspend = suspend();
@ -103,6 +114,8 @@ export function async_derived(fn) {
if (promise === current) {
restore();
from_async_derived = null;
internal_set(value, v);
}
} catch (e) {

@ -37,6 +37,7 @@ import {
destroy_derived,
destroy_derived_effects,
execute_derived,
from_async_derived,
update_derived
} from './reactivity/deriveds.js';
import * as e from './errors.js';
@ -51,6 +52,7 @@ import {
set_dev_current_component_function
} from './context.js';
import { add_boundary_effect, commit_boundary } from './dom/blocks/boundary.js';
import * as w from './warnings.js';
const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
@ -967,6 +969,15 @@ export function get(signal) {
captured_signals.add(signal);
}
if (DEV && from_async_derived) {
var tracking = (from_async_derived.f & REACTION_IS_UPDATING) !== 0;
var was_read = from_async_derived.deps !== null && from_async_derived.deps.includes(signal);
if (!tracking && !was_read) {
w.await_reactivity_loss();
}
}
// Register the dependency on the current reaction signal.
if (active_reaction !== null && !untracking) {
if (derived_sources !== null && derived_sources.includes(signal)) {

@ -18,6 +18,17 @@ export function assignment_value_stale(property, location) {
}
}
/**
* Detected reactivity loss
*/
export function await_reactivity_loss() {
if (DEV) {
console.warn(`%c[svelte] await_reactivity_loss\n%cDetected reactivity loss\nhttps://svelte.dev/e/await_reactivity_loss`, bold, normal);
} else {
console.warn(`https://svelte.dev/e/await_reactivity_loss`);
}
}
/**
* Detected an unnecessary async waterfall
*/

Loading…
Cancel
Save