Svelte: Unexpected Update Calls

Created on 26 Jul 2019  Â·  5Comments  Â·  Source: sveltejs/svelte

Describe the bug
beforeUpdate is called twice when using bind:this to the same variable in logic blocks. Even though afterUpdate is schedule to be called after the last beforeUpdate it isn't

UPDATE: Exists even if bound to two different variables

Logs
REPL log

> Before null 
> After <button class="ui button">
> Before <button class="ui button">

To Reproduce
https://svelte.dev/repl/d85b4344f4044c4489b4e0260eabf475?version=3.6.8 (same variables)
https://svelte.dev/repl/7b1deb63003544358a6c4ee10ae28dcf?version=3.6.8 (different variables)

Expected behavior
If a single cycle isn't achieved, it should complete the cycle

> Before null 
> After <button class="ui button">
> Before <button class="ui button">
> After <button class="ui button">

Stacktraces


Stack trace

Error: "Custom message to generate Stack trace: beforeUpdate #counter-0 elasped-time(ms) 4"
    instance Button.svelte:43
    run index.mjs:18
    run_all index.mjs:24
    init index.mjs:1249
    Button bundle.js:896
    create_else_block$1 bundle.js:1105
    create_fragment$2 bundle.js:1316
    init index.mjs:1250
    SvelteMantic bundle.js:1403
    app index.js:9
    <anonymous> bundle.js:1429
Button.svelte:45:22

Error: "Custom message to generate Stack trace: afterUpdate #counter-1 elasped-time(ms) 18"
    instance Button.svelte:55
    flush index.mjs:570
    init index.mjs:1299
    SvelteMantic bundle.js:1403
    app index.js:9
    <anonymous> bundle.js:1429
bundle.js:826:18

Error: "Custom message to generate Stack trace: beforeUpdate #counter-2 elasped-time(ms) 20"
    instance Button.svelte:43
    run index.mjs:18
    run_all index.mjs:24
    update index.mjs:604
    flush index.mjs:560
    init index.mjs:1299
    SvelteMantic bundle.js:1403
    app index.js:9
    <anonymous> bundle.js:1429
Button.svelte:45:22

Error: "Custom message to generate Stack trace: Flush() elapsed-time(ms) 21"
    flush index.mjs:582
    init index.mjs:1299
    SvelteMantic bundle.js:1403
    app index.js:9
    <anonymous> bundle.js:1429
index.mjs:584:8

Error: "Custom message to generate Stack trace: Flush() elapsed-time(ms) 22"
    flush index.mjs:582
index.mjs:584:8

​

Information about your Svelte project:

  • Your browser and the version: Firefox 67
  • Your operating system: Ubuntu 18 LTS

  • Svelte version 3.6.8

  • Rollup

Severity
Severity is High, as the the cycle should always end with an afterUpdate and not beforeUpdate

bug has pr

Most helpful comment

It still have the same problem.
https://svelte.dev/repl/3381c9b40dc8441a8e4ebfa48fd8c178?version=3.26.0

REPL Logs
"beforeUpdate"
"afterUpdate"
"beforeUpdate"

All 5 comments

Probably simpler example:
https://svelte.dev/repl/8a96e6e545244bff9fd0125b152d6840?version=3.6.9

So it seems that the bind:this will create binding_callbacks in flush which will invalidate the bound variable:
https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L46
This invalidate will add a dirty component and therefore execute the loop again, triggering an extra beforeUpdate and an extra afterUpdate, but his special seen_callbacks code will prevent the afterUpdate being triggered again for the same cycle:
https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L48-L59

This checking on seen_callbacks is in de code since the reactive assignments have been implemented, so basically since Svelte 3.

So it seems that the bind:this will create binding_callbacks in flush which will invalidate the bound variable:

https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L46

This invalidate will add a dirty component and therefore execute the loop again, triggering an extra beforeUpdate and an extra afterUpdate, but his special seen_callbacks code will prevent the afterUpdate being triggered again for the same cycle:

https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L48-L59

This checking on seen_callbacks is in de code since the reactive assignments have been implemented, so basically since Svelte 3.

Exactly, it took me a while to figure it while I was going through my bundle js file but it seems that if the bindings are invalidated before the dirty components are scheduled for an update the beforeUpdate may run multiple times but will end in an afterUpdate, i.e, basically move this

https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L46

before (this can lead to unpredictable side effects, but I can't think of any)

https://github.com/sveltejs/svelte/blob/f65ce85748ffb85f034f1dd001f953979e97faa0/src/runtime/internal/scheduler.ts#L40-L44

resulting in

> Before
> Before
> After

or just

> Before
> After

This is pretty severe. Can't build anything serious with Svelte until this is fixed.

This appears to have been fixed as of 3.18.2.

It still have the same problem.
https://svelte.dev/repl/3381c9b40dc8441a8e4ebfa48fd8c178?version=3.26.0

REPL Logs
"beforeUpdate"
"afterUpdate"
"beforeUpdate"

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matt3224 picture matt3224  Â·  3Comments

noypiscripter picture noypiscripter  Â·  3Comments

lnryan picture lnryan  Â·  3Comments

davidcallanan picture davidcallanan  Â·  3Comments

st-schneider picture st-schneider  Â·  3Comments