Realm-js: Promises are not resolved inside change listeners callbacks until tapping the screen

Created on 28 Feb 2020  路  4Comments  路  Source: realm/realm-js

When my app start I show a spinner until the synchronization of my query-synched realm completes.

Goals

When the sync ends the spinner disappears because of the promise resolved.

Expected Results

The promise is resolved and the code go on.

Actual Results

The problem is that since the promises are not resolved until I tap the screen the loading process seems infinite and the spinner doesn't disappear.

Steps to Reproduce

I have this problem since almost 1 year. You can reproduce it by:

  • use create-react-native-app
  • install realm
  • try

Code Sample

        var realm = Database.getRealm()

        var class1 = realm.objects("Class1")
        var class2 = realm.objects("Class2")
        var class3 = realm.objects("Class3")

        await Promise.all(
            [
                Database.susbscribeAndSyncTo(class1),
                Database.susbscribeAndSyncTo(class2),
                Database.susbscribeAndSyncTo(class3),
            ]
        )

        // This console.log is not executed until I don't tap on the screen.  
        // More classes I add to this and more times I need to tap the screen
        console.log("Synched")

        return true

static susbscribeAndSyncTo = async (object, object_name) => {
        var subscription = object.subscribe()

        return new Promise((resolve, reject) => {
            subscription.addListener((subscription, state) => {
                if (this.checkSubscriptionState(state, object_name)) {
                    try {
                        subscription.removeAllListeners()
                    } catch (e) {
                        console.log(e.message)
                    }
                    resolve(true);
                }
            })
        });
    }
    static checkSubscriptionState = (state, object_type) => {
        switch (state) {
            case Realm.Sync.SubscriptionState.Creating:
                // The subscription has not yet been written to the Realm
                break;
            case Realm.Sync.SubscriptionState.Pending:
                // The subscription has been written to the Realm and is waiting
                // to be processed by the server
                break;
            case Realm.Sync.SubscriptionState.Complete:
                // The subscription has been processed by the server and all objects
                // matching the query are in the local Realm
                return true

                break;
            case Realm.Sync.SubscriptionState.Invalidated:
                // The subscription has been removed
                break;
            case Realm.Sync.SubscriptionState.Error:
                break;

            default:
                break;
        }

        return false
    }

Version of Realm and Tooling

  • Realm JS SDK Version: Realm JS from 3.4.2
  • Node or React Native: React Native
  • Client OS & Version: Android / iOS
  • Which debugger for React Native: None
O-Community

Most helpful comment

Solved like this

static susbscribeAndSyncTo = async (object, object_name) => {
        var subscription = object.subscribe()

        return new Promise((resolve, reject) => {
            subscription.addListener((subscription, state) => {
                if (this.checkSubscriptionState(state, object_name)) {
                    try {
                        subscription.removeAllListeners()
                    } catch (e) {
                        console.log(e.message)
                    }

                    setTimeout(() => null, 30) // Workaround
                    resolve(true);
                    setTimeout(() => null, 30) // Workaround
                }
            })
        });
    }

All 4 comments

Hi @aureliopetrone ,

I did not test your code yet but looking at the code provided, the call to new Promise will not resolve/reject if the if statement is false.

I'm talking about this:
return new Promise((resolve, reject) => { subscription.addListener((subscription, state) => { if (this.checkSubscriptionState(state, object_name)) { try { subscription.removeAllListeners() } catch (e) { console.log(e.message) } resolve(true); } }) });

Try to add a resolve or reject after if (this.checkSubscriptionState(state, object_name)). The promise should complete then

@dlombard but actually there is no error because as I said if I tap everything is ok and the app sync.

We have this exact problem too!

Solved like this

static susbscribeAndSyncTo = async (object, object_name) => {
        var subscription = object.subscribe()

        return new Promise((resolve, reject) => {
            subscription.addListener((subscription, state) => {
                if (this.checkSubscriptionState(state, object_name)) {
                    try {
                        subscription.removeAllListeners()
                    } catch (e) {
                        console.log(e.message)
                    }

                    setTimeout(() => null, 30) // Workaround
                    resolve(true);
                    setTimeout(() => null, 30) // Workaround
                }
            })
        });
    }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ashah888 picture ashah888  路  3Comments

CrystalRanita picture CrystalRanita  路  3Comments

blagoev picture blagoev  路  3Comments

jmartindivmedianet picture jmartindivmedianet  路  3Comments

max-zu picture max-zu  路  3Comments