Skip to content
23 changes: 14 additions & 9 deletions src/runtime/internal/scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { run_all } from './utils';
import { set_current_component } from './lifecycle';
import { run_all, Queue } from './utils';
import { get_current_component, set_current_component } from './lifecycle';

export const dirty_components = [];
export const dirty_components = new Queue<any>();
export const intros = { enabled: false };

export const binding_callbacks = [];
Expand Down Expand Up @@ -31,17 +31,21 @@ export function add_flush_callback(fn) {
flush_callbacks.push(fn);
}

let flushing = false;
const seen_callbacks = new Set();
export function flush() {
if (flushing) return;
flushing = true;

let current_component = null;
try {
current_component = get_current_component();
} catch {
// no current component, so leave it as null
}

do {
// first, call beforeUpdate functions
// and update components
for (let i = 0; i < dirty_components.length; i += 1) {
const component = dirty_components[i];
while (dirty_components.length) {
const component = dirty_components.shift();
set_current_component(component);
update(component.$$);
}
Expand All @@ -68,12 +72,13 @@ export function flush() {
render_callbacks.length = 0;
} while (dirty_components.length);

set_current_component(current_component);

while (flush_callbacks.length) {
flush_callbacks.pop()();
}

update_scheduled = false;
flushing = false;
seen_callbacks.clear();
}

Expand Down
34 changes: 34 additions & 0 deletions src/runtime/internal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ export function is_empty(obj) {
return Object.keys(obj).length === 0;
}

export class Queue<T> {
forward: T[];
reverse: T[];

constructor() {
this.forward = [];
this.reverse = [];
}
push(value: T) {
return this.forward.push(value);
}
shift() {
if (this.reverse.length === 0) {
while (this.forward.length) {
this.reverse.push(this.forward.pop());
}
}
return this.reverse.pop();
}
get length() {
return this.forward.length + this.reverse.length;
}
set length(len: number) {
if (len === 0) {
this.forward.length = 0;
this.reverse.length = 0;
} else {
while (this.length > len) {
this.shift();
}
}
}
}

export function validate_store(store, name) {
if (store != null && typeof store.subscribe !== 'function') {
throw new Error(`'${name}' is not a store with a 'subscribe' method`);
Expand Down
15 changes: 15 additions & 0 deletions test/runtime/samples/component-binding-onMount/Mount.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script>
import { onMount } from 'svelte';

let element;
let bound = false;
onMount(() => {
if (element) bound = true;
});

</script>

<div bind:this={element}></div>
<p>
Bound? {bound}
</p>
11 changes: 11 additions & 0 deletions test/runtime/samples/component-binding-onMount/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
async test({ assert, target }) {
assert.htmlEqual(target.innerHTML, `
<div id="target"><div></div>
<p>
Bound? true
</p>
</div>
`);
}
};
13 changes: 13 additions & 0 deletions test/runtime/samples/component-binding-onMount/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
import Mount from './Mount.svelte';
import { onMount } from 'svelte';

onMount(() => {
const component = new Mount({
target: document.querySelector('#target'),
props: {},
});
});
</script>

<div id="target" />