使用侦听器加入Firebase表格?

时间:2017-09-25 22:48:17

标签: javascript firebase firebase-realtime-database

使用child_addedchild_changedchild_removed听众将两个或多个Firebase表连接在一起是否可行?

例如,假设您有两个表。一个包含有关用户的基本信息,另一个包含用户与角色的关系。

用户

{
    "1":
    {
        "forename": "Joe",
        "surname": "Bloggs"
    },
    "2":
    {
        "forename": "Jane",
        "surname": "Doe"
    },
    "3":
    {
        "forename": "Luke",
        "surname": "Skywalker"
    }
}

用户 - 角色关系

{
    "a":
    {
        "userId": 1,
        "roleId": 2
    },
    "b":
    {
        "userId": 2,
        "roleId": 2
    },
    "c":
    {
        "userId": 3,
        "roleId": 4
    }
}

加入

如果您想要检索角色为2的所有用户,则可以使用orderByChildequalTo使用roleId编写正常的Firebase查询。对于每个child_added,您可以使用child_added为每个相关用户收听orderByChild。然后,两个文档中的值可以汇总到您的应用程序使用的单个对象中。它看起来可能如下所示。

代码

function join(initial, joins, callback)
{
    const result = [];
    initial.query.on
    (
        'child_added',
        function(initialSnapshot)
        {
            const initialChild = initialSnapshot.val();
            let initialResult = initialChild;
            const resultIndex = result.push(initialResult) - 1;
            joins.forEach
            (
                function(join)
                {
                    const delay = Math.floor(resultIndex / LISTENER_BATCH_LENGTH);
                    setTimeout
                    (
                        function()
                        {
                            join.query(initialChild);
                            let joinResultPrevious = null;
                            const addedCallback = joinQuery.on
                            (
                                'child_added',
                                function(joinSnapshot)
                                {
                                    const joinChild = joinSnapshot.val();
                                    const joinResult = joinChild;
                                    joinResultPrevious = joinResult;
                                    initialResult = Object.assign(initialResult, joinResult);
                                    callback(result);
                                }
                            );
                            joinQuery.on
                            (
                                'child_changed',
                                function(joinSnapshot)
                                {
                                    const joinChild = joinSnapshot.val();
                                    const joinResult = joinChild;
                                    const deletedProperties = getMissingProperties(joinResult, joinResultPrevious);
                                    deletedProperties.forEach
                                    (
                                        function(property)
                                        {
                                            delete initialResult[property];
                                        }
                                    );
                                    initialResult = Object.assign(initialResult, joinResult);
                                    joinResultPrevious = joinResult;
                                    callback(result);
                                }
                            );
                            joinQuery.on
                            (
                                'child_removed',
                                function()
                                {
                                    result.splice(resultIndex, 1);
                                    callback(result);
                                }
                            );
                        },
                        delay
                    );
                );
            }
        );
    };

性能

麻烦的是,我已经尝试过这个功能,虽然它有效,但它的工作速度非常慢。我测试了大约2,100个用户文档及其相应的用户角色关系文档。使用Chrome的分析工具,大部分CPU时间似乎花费在Firebase的某些部分上。我不知道这是哪个部分,因为函数名称似乎被混淆了,其中一个昂贵的函数被标记为Qa。或许浏览器根本无法做到这么多工作。但是,我确实想知道Firebase是否会产生数千个独立请求,而将它们组合在一起可能要便宜得多。无论哪种方式,考虑到明显的性能问题,了解以这种方式连接表是否可行将是有用的。

更新

我似乎在很大程度上解决了性能问题。它们似乎源于Firebase以某种方式锁定了浏览器线程。为加入侦听器引入一个带有setTimeout的批量延迟似乎可以释放对其他进程的控制,包括DOM,它可以提供更平滑,更快速的用户体验。

0 个答案:

没有答案