Skip to content

svelte/Infinite-reactive-loop #299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
baseballyama opened this issue Nov 5, 2022 · 0 comments · Fixed by #332
Closed

svelte/Infinite-reactive-loop #299

baseballyama opened this issue Nov 5, 2022 · 0 comments · Fixed by #332
Labels
enhancement New feature or request new rule

Comments

@baseballyama
Copy link
Member

baseballyama commented Nov 5, 2022

Motivation

I saw that one of the Svelte users faced an infinite loop.
https://twitter.com/knaka/status/1588160616300433411?s=20&t=R5g8ssKc6yXRpZ-va-hrWQ

So I would like to detect such situations automatically by ESLint.

Description

Svelte runtime prevents calling the same reactive statement twice in a microtask.
But between different microtask, it doesn't prevent.

https://svelte.dev/repl/f0d31c7d19584c45af19c87ff06c568c?version=3.52.0

I think this rule has a limitation if a reactive statement depends on the store. (Please see store2 example below)
But I believe this rule is helpful for detecting an infinity loop.

Examples

<script>
  import { store1, store2, store3 } from './store.js'
  const Promise2 = Promise
  let a = 0;
  let b = 0;
  let c = 0;
  let d = 0;
  let e = 0;
  let f = 0;
  let g = 0;
  let h = 0;
  let i = 0;

  // ✗ BAD
  $: (async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        a = a + 1;
      }, 100)
    })
  })();

  $: new Promise((resolve) => {
    setTimeout(() => {
      b = b + 1;
    }, 100)
  })

  $: {
    new Promise((resolve) => {
      setTimeout(() => {
        c = c + 1;
      }, 100)
    })
  }

  $: (() => {
    new Promise((resolve) => {
      setTimeout(() => {
        d = d + 1;
      }, 100)
    })
  })();

  $: new Promise(() => {
    setTimeout(() => {
      e = e + 1;
    }, 100)
  })

  $: new Promise2(() => {
    setTimeout(() => {
      f = f + 1;
    }, 100)
  })

  $: {
    Promise.all([
      new Promise(() => { throw Error('') })
    ]).catch((err) => {
      setTimeout(() => {
        g = g + 1;
      }, 100)
    });
  }

  const funcH = async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        h = h + 1;
      }, 100)
    })
  }
  $: (async () => { h; await funcH() })();

  $: (async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        $store1 = $store1 + 1;
      }, 100)
    })
  })();

  // I think it's impossible to check if `funcStore2` defined at different file.
  const funcStore2 = async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        $store2 = $store2 + 1;
      }, 100)
    })
  }
  $: (async () => { $store2; await funcStore2() })();

  // ✓ GOOD
  // This doesn't have infinite reactive
  const funcI = async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        i = i + 1;
      }, 100)
    })
  }
  $: (async () => { await funcI() })();

  const funcStore3 = async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        $store3 = $store3 + 1;
      }, 100)
    })
  }
  $: (async () => { await funcStore3() })();
</script>

<p>a: {a}</p>
<p>b: {b}</p>
<p>c: {c}</p>
<p>d: {d}</p>
<p>e: {e}</p>
<p>f: {f}</p>
<p>g: {g}</p>
<p>h: {h}</p>
<p>store1: {$store1}</p>
<p>store2: {$store2}</p>
<br />
<p>i: {i}</p>
<p>store3: {$store3}</p>

Additional comments

No response

@baseballyama baseballyama added enhancement New feature or request new rule labels Nov 5, 2022
@baseballyama baseballyama changed the title svelte/infinity-reactive-loop svelte/Infinite-reactive-loop Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request new rule
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant