adjust heuristic

pull/11820/head
Dominic Gannaway 2 years ago
parent e5d9eba2b2
commit 8738c13107

@ -36,6 +36,7 @@ export const RawTextElements = ['textarea', 'script', 'style', 'title'];
export const DelegatedEvents = [
'beforeinput',
'click',
'submit',
'change',
'dblclick',
'contextmenu',

@ -39,6 +39,7 @@ let current_scheduler_mode = FLUSH_MICROTASK;
// Used for handling scheduling
let is_micro_task_queued = false;
let is_yield_task_queued = false;
let is_yield_task_active = false;
export let is_flushing_effect = false;
export let is_destroying_effect = false;
@ -574,6 +575,7 @@ function flush_queued_effects(effects) {
function process_deferred() {
is_micro_task_queued = false;
is_yield_task_queued = false;
is_yield_task_active = false;
if (flush_count > 101) {
return;
}
@ -588,8 +590,11 @@ function process_deferred() {
async function yield_tick() {
// TODO: replace this with scheduler.yield when it becomes standard
await new Promise((fulfil) => {
requestAnimationFrame(() => {
setTimeout(fulfil, 0);
queueMicrotask(() => {
is_yield_task_active = true;
requestAnimationFrame(() => {
setTimeout(fulfil, 0);
});
});
// In case of being within background tab, the rAF won't fire
setTimeout(fulfil, 100);
@ -722,11 +727,14 @@ function process_effects(effect, collected_effects) {
*/
export function yield_updates(fn) {
const previous_scheduler_mode = current_scheduler_mode;
// If we're calling yield_updates, and we've already yielded some updates then it's likely
// that the event might might try and read from the UI. In order for this to be glitch free,
// we can flush any changes, forcing the UI to be up-to-date, so any reads from the UI work as
// expected.
if (previous_scheduler_mode !== FLUSH_YIELD && is_yield_task_queued && !is_micro_task_queued) {
// If we're calling yield_updates and there is already an active yield in progress (is_yield_task_active)
// then it's likely that the event might might try and read from the UI. Additionally, we might be dealing with
// event that was sync called from another event flow, thus isTrusted() will be true such as a submit event from
// a subsequent click event. In either case, the UI needs to be up-to-date, so we flush any pending changes.
if (
previous_scheduler_mode !== FLUSH_YIELD &&
(is_yield_task_active || (is_yield_task_queued && window.event?.isTrusted))
) {
flush_sync();
}
try {
@ -758,6 +766,7 @@ export function flush_sync(fn, flush_previous = true) {
current_queued_root_effects = root_effects;
is_yield_task_queued = false;
is_micro_task_queued = false;
is_yield_task_active = false;
if (flush_previous) {
flush_queued_root_effects(previous_queued_root_effects);

@ -1,3 +1,4 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
@ -22,15 +23,15 @@ export default test({
<input type="checkbox" value="c" data-index="z-2">
`,
async test({ assert, target, window }) {
test({ assert, target, window }) {
const inputs = target.querySelectorAll('input');
const checked = new Set();
/** @param {number} i */
const checkInbox = async (i) => {
const checkInbox = (i) => {
checked.add(i);
inputs[i].checked = true;
await inputs[i].dispatchEvent(event);
inputs[i].dispatchEvent(event);
};
for (let i = 0; i < 18; i++) {
@ -39,17 +40,20 @@ export default test({
const event = new window.Event('change');
await checkInbox(2);
checkInbox(2);
flushSync();
for (let i = 0; i < 18; i++) {
assert.equal(inputs[i].checked, checked.has(i));
}
await checkInbox(12);
checkInbox(12);
flushSync();
for (let i = 0; i < 18; i++) {
assert.equal(inputs[i].checked, checked.has(i));
}
await checkInbox(8);
checkInbox(8);
flushSync();
for (let i = 0; i < 18; i++) {
assert.equal(inputs[i].checked, checked.has(i));
}

@ -1,3 +1,4 @@
import { flushSync } from 'svelte';
import { ok, test } from '../../test';
export default test({
@ -16,6 +17,7 @@ export default test({
input.value = '5.';
input.dispatchEvent(inputEvent);
flushSync();
// input type number has value === "" if ends with dot/comma
assert.equal(component.value, undefined);
@ -23,12 +25,14 @@ export default test({
input.value = '5.5';
input.dispatchEvent(inputEvent);
flushSync();
assert.equal(component.value, 5.5);
assert.equal(input.value, '5.5');
input.value = '5.50';
input.dispatchEvent(inputEvent);
flushSync();
assert.equal(component.value, 5.5);
assert.equal(input.value, '5.50');

@ -2,7 +2,7 @@ import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test({ assert, target, logs }) {
async test({ assert, target, logs }) {
const [b1] = target.querySelectorAll('button');
b1.click();
flushSync();

@ -2,9 +2,11 @@ import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test({ assert, target, logs }) {
async test({ assert, target, logs }) {
const [b1] = target.querySelectorAll('button');
b1.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
// The browser will yield a microtask between events
await Promise.resolve();
b1.click();
flushSync();

Loading…
Cancel
Save