diff --git a/docs/sync.js b/docs/sync.js index ff4dbf26..65d6520f 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -119,9 +119,10 @@ class Sync { * Change information passed when receiving sync `'change'` events. * * A ChangeEvent object can only be used within the callback which it is - * supplied to, and cannot be stored for use later. In particular, this means - * that async functions cannot be used within the callback prior to accessing - * the change event. The Realms supplied by the change event do not need to be + * supplied to, and cannot be stored for use later. If the callback returns a + * promise, the ChangeEvent will remain valid until that promise is resolved + * (and no further notifications for that same Realm will be made until it is + * resolved). The Realms supplied by the change event do not need to be * explicitly closed. * * @memberof Realm.Sync diff --git a/lib/index.d.ts b/lib/index.d.ts index 746f84ad..130a8145 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -408,7 +408,8 @@ declare namespace Realm.Sync { } function addListener(serverURL: string, adminUser: Realm.Sync.User, regex: string, name: string, changeCallback: (changeEvent: ChangeEvent) => void): void; - function removeAllListeners(name?: string): void; + function addListener(serverURL: string, adminUser: Realm.Sync.User, regex: string, name: string, changeCallback: (changeEvent: ChangeEvent) => Promise): void; + function removeAllListeners(): Promise; function removeListener(regex: string, name: string, changeCallback: (changeEvent: ChangeEvent) => void): void; function setLogLevel(logLevel: 'all' | 'trace' | 'debug' | 'detail' | 'info' | 'warn' | 'error' | 'fatal' | 'off'): void; function initiateClientReset(path: string): void; diff --git a/lib/notifier.js b/lib/notifier.js index 30f45e63..c8f43f86 100644 --- a/lib/notifier.js +++ b/lib/notifier.js @@ -57,12 +57,14 @@ class FunctionListener { onchange(changes) { if (this.event !== 'change' || !this.regex.test(changes.path)) { + changes.release(); return; } if (changes.isEmpty) { + changes.release(); return; } - this.fn(changes); + Promise.resolve(this.fn(changes)).then(() => changes.release()); } }; @@ -125,12 +127,17 @@ class Listener { if (!changes) { return; } + + let refCount = this.callbacks.length; + changes.release = () => { + if (--refCount === 0) { + changes.close(); + } + } + for (const callback of this.callbacks) { callback.onchange(changes); } - if (!changes.refCount) { - changes.close(); - } } available(virtualPath) { diff --git a/lib/worker.js b/lib/worker.js index 4afbce55..77a8f8bc 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -80,9 +80,7 @@ class Worker { if (m.change) { const changeObj = this._changeObjects[m.change]; delete this._changeObjects[m.change]; - if (--changeObj.refCount === 0) { - changeObj.close(); - } + changeObj.release(); } this._waiting.push(child); this._next();