Repository: sveltejs/svelte (JavaScript)
Date: 2020-10-15 20:26:55+00:00
Task type: Bug Fix

Issue:
Destructured promise result in {#await} becomes undefined during re-render
**Describe the bug**
Values in a destructured promise result become undefined after a re-render.

```html
<script>
	let test = 0;

	$: promise = Promise.resolve({ data: 1 });
</script>

{#await promise then { data }}
	{#if data}
		<button on:click={() => (test = 1)}>Test</button>
	{:else}data is {data}{/if}
{/await}
```

For some reason, having promise defined in a reactive statement was necessary here to reproduce the bug. In my project, I was calling a function in the `{#await}` block and passing it a store value.

**Logs**
N/A

**To Reproduce**
https://svelte.dev/repl/3fd4e2cecfa14d629961478f1dac2445?version=3.29.0

**Expected behavior**
I would expect promise results to persist between renders.

**Stacktraces**
N/A

**Information about your Svelte project:**
- Your browser and the version: (e.x. Chrome 52.1, Firefox 48.0, IE 10)
Chrome, Firefox

- Your operating system: (e.x. OS X 10, Ubuntu Linux 19.10, Windows XP, etc)
Arch Linux

- Svelte version (Please check you can reproduce the issue with the latest release!)
3.29.0

- Whether your project uses Webpack or Rollup
N/A

**Severity**
This is annoying, but I can avoid using destructuring here to get around the problem.

**Additional context**
N/A

Destructured promise result in {#await} becomes undefined during re-render
**Describe the bug**
Values in a destructured promise result become undefined after a re-render.

```html
<script>
	let test = 0;

	$: promise = Promise.resolve({ data: 1 });
</script>

{#await promise then { data }}
	{#if data}
		<button on:click={() => (test = 1)}>Test</button>
	{:else}data is {data}{/if}
{/await}
```

For some reason, having promise defined in a reactive statement was necessary here to reproduce the bug. In my project, I was calling a function in the `{#await}` block and passing it a store value.

**Logs**
N/A

**To Reproduce**
https://svelte.dev/repl/3fd4e2cecfa14d629961478f1dac2445?version=3.29.0

**Expected behavior**
I would expect promise results to persist between renders.

**Stacktraces**
N/A

**Information about your Svelte project:**
- Your browser and the version: (e.x. Chrome 52.1, Firefox 48.0, IE 10)
Chrome, Firefox

- Your operating system: (e.x. OS X 10, Ubuntu Linux 19.10, Windows XP, etc)
Arch Linux

- Svelte version (Please check you can reproduce the issue with the latest release!)
3.29.0

- Whether your project uses Webpack or Rollup
N/A

**Severity**
This is annoying, but I can avoid using destructuring here to get around the problem.

**Additional context**
N/A



Issue discussion:

Solution patch:
diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
--- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
@@ -96,7 +96,7 @@ class AwaitBlockBranch extends Wrapper {
 		`);
 		this.block.chunks.declarations.push(b`${get_context}(#ctx)`);
 		if (this.block.has_update_method) {
-			this.block.chunks.update.push(b`${get_context}(#ctx)`);
+			this.block.chunks.update.unshift(b`${get_context}(#ctx)`);
 		}
 	}
 }


Test patch:
diff --git a/test/runtime/samples/await-then-destruct-object-if/_config.js b/test/runtime/samples/await-then-destruct-object-if/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-object-if/_config.js
@@ -0,0 +1,29 @@
+export default {
+	props: {
+		thePromise: Promise.resolve({ result: 1 })
+	},
+
+	html: '',
+
+	async test({ assert, component, target }) {
+		await (component.thePromise = Promise.resolve({ result: 1 }));
+
+		assert.htmlEqual(
+			target.innerHTML,
+			`
+				<p>result: 1</p>
+				<p>count: 0</p>
+			`
+		);
+
+		await new Promise(resolve => setTimeout(resolve, 1));
+
+		assert.htmlEqual(
+			target.innerHTML,
+			`
+				<p>result: 1</p>
+				<p>count: 1</p>
+			`
+		);
+	}
+};
diff --git a/test/runtime/samples/await-then-destruct-object-if/main.svelte b/test/runtime/samples/await-then-destruct-object-if/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/await-then-destruct-object-if/main.svelte
@@ -0,0 +1,19 @@
+<script>
+	export let thePromise;
+
+	let count = 0;
+
+	setTimeout(() => {
+		count++;
+	}, 0);
+</script>
+
+{#await thePromise then { result }}
+	{#if result}
+		<p>result: {result}</p>
+		<p>count: {count}</p>
+	{:else}
+		<p>result: {result}</p>
+		<p>count: {count}</p>
+	{/if}
+{/await}