Svelte: destroy function returned from onMount is not called if onMount is passed an async function

Created on 29 May 2020  路  7Comments  路  Source: sveltejs/svelte

Describe the bug
What I need is to use async-await in onMount().
_Or maybe you can suggest me what is wrong and what I can use alternatively._

To Reproduce

  1. go here: https://svelte.dev/repl/000ae69c0fe14d9483678d4ace874726?version=3.23.0
  2. open the console
  3. click on the button
  4. you should see messages: "Mounting..." and "A lot of background work..."
  5. if you click again the destroy message is not written

WHY?

Did onMount() recognizes the promise? Should it?

Expected behavior
I need that async behavior because I need to wait for function lazyLoading() before rendering the Child component.

Is there an alternative way to do this in Svelte?

compiler warning docs

Most helpful comment

i feel it should get a runtime warning / error, if it returns something besides function or undefined.

that's also how react is handling useEffect, which i find it reasonable

All 7 comments

I don't know much about svelte internals yet, but you should do like this.

// NG
onMount(async () => {
  await xxx();
});

// OK
onMount(() => {
  (async () => {
    await xxx();
  })();
});

@frederikhors I'm pretty sure this is a bug. It seems that if you use an async function then onDestroy is not properly wired up.

I'm going to rename this issue for you and mark it as a bug.

This isn't really a bug, because if you have an async function that returns a function, it doesn't really return a function - it returns a promise. I don't remember whether the Svelte internals currently check for the onMount callback's return being a function or whether they check for it being truthy. Maybe there's some adjustment to be made there.

But the point is that, if onMount's callback does return a promise, how should Svelte handle that? What if the promise hasn't resolved yet by the time the component is destroyed? What do we do? If we're saying the the onMount callback needs to return a function or nothing, this is probably why.

i feel it should get a runtime warning / error, if it returns something besides function or undefined.

that's also how react is handling useEffect, which i find it reasonable

@tanhauhau I'm not sure I agree. Using an async function in onMount is a common use-case (for example, we tell people to use await import there for client-side only libraries in Sapper.

What I believe should happen is the Svelte compiler should, when a promise is passed to onMount, realise that a promise has been passed, and await the result of the function to be used as the onDestroy function.

i.e, it should behave the exact same way for an async function as it does for a non-async function (if this is possible)

It's not a bug, checking whether the returned value is a promise as @antony suggests really wouldn't be a big deal though, if that helps somebody ?

There's another problem however, async functions are run ( wait for it ) asynchronously, meaning that they will actually run _afterFlush鈩.

Accepting async lifecycle functions therefore would bring confusion as to why async onMount functions ( that you specifically said were allowed and supported in the documentation ) aren't run onMount but after flush.

it all ties back to the same problem which is about general javascript knowledge.
So @tanhauhau is correct, it should throw an error.

Yeah what he said... that teaches me to leave a reply open while I get lunch....

Anyways, I just see all sorts of potential for deadlock relying on a promise for onDestroy that may never resolve.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matt3224 picture matt3224  路  3Comments

davidcallanan picture davidcallanan  路  3Comments

robnagler picture robnagler  路  3Comments

plumpNation picture plumpNation  路  3Comments

AntoninBeaufort picture AntoninBeaufort  路  3Comments