From e25b7df27518961996101b374d424f21d6718996 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Wed, 24 Apr 2019 19:05:03 -0700 Subject: [PATCH 1/2] fix: Ensure RxJS users don't create memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a bit of excitement in the RxJS community about Svelte. - It seems like the rest of Svelte "just works™" with RxJS! - **BUT** The danger is that unwary users will figure out how smooth this API is and accidentally create nasty memory leaks if the returned RxJS Subscriptions are not handled. Fortunately the required change is small. NOTE: I am not entirely sure how to test this change. The goal here is to make sure that whenever you would normally teardown your store subscriptions, it is also tearing down these RxJS-shaped subscriptions. This is most commonly something you want in a component scenario. Say you have a timer component in your app that you show and remove with an `{#if}` block, when the `{#if}` block hides the component, you'd want to tear down the underlying Observable that is "ticking". Related #2549 --- src/internal/utils.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/internal/utils.js b/src/internal/utils.js index 5e2f8b1165..ea3f2ddde5 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -48,7 +48,12 @@ export function validate_store(store, name) { } export function subscribe(component, store, callback) { - component.$$.on_destroy.push(store.subscribe(callback)); + let unsub = store.subscribe(callback); + // Prevent memory leaks for RxJS users. + if (typeof unsub === 'object' && typeof unsub.unsubscribe === 'function') { + unsub = () => unsub.unsubscribe(); + } + component.$$.on_destroy.push(unsub); } export function create_slot(definition, ctx, fn) { @@ -74,4 +79,4 @@ export function exclude_internal_props(props) { const result = {}; for (const k in props) if (k[0] !== '$') result[k] = props[k]; return result; -} \ No newline at end of file +} From 2eba37bdb18ea469c5def44269b31e72ea6f6c32 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 24 Apr 2019 20:55:15 -0700 Subject: [PATCH 2/2] RxJS always returns a Subscription object with an unsubscribe. Co-Authored-By: benlesh --- src/internal/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/utils.js b/src/internal/utils.js index ea3f2ddde5..f773be639d 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -50,7 +50,7 @@ export function validate_store(store, name) { export function subscribe(component, store, callback) { let unsub = store.subscribe(callback); // Prevent memory leaks for RxJS users. - if (typeof unsub === 'object' && typeof unsub.unsubscribe === 'function') { + if (unsub.unsubscribe) { unsub = () => unsub.unsubscribe(); } component.$$.on_destroy.push(unsub);