为什么AngularFire比普通的Firebase API慢得多

时间:2014-01-28 19:39:15

标签: performance firebase angularfire

在使用AngularFire测试Firebase时,我对它的速度感到惊讶。经过进一步的测试,我发现Firebase不是很慢,但是AngularFire很慢(在Firefox v26.0中非常慢)。

我的用例是我需要访问给定父级的多个孩子的地方。孩子的总数可能会达到数千人,因此不能同时取出所有孩子。此外,他们需要从祖父母那里访问,因此优先查询并不总是一种选择。

在这个使用AngularFire(慢)的示例中,我有什么问题吗? http://plnkr.co/edit/eML3HF3RtchIU26EGVaw?p=preview

使用AngularFire访问儿童的要点:

function getChild(childID) {
    recordCount++;
    myC.children[childID] = $firebase(new Firebase(childrenUrl + childID));

    myC.children[childID].$on('loaded', function () {
        returnCount++;
        checkReturnCount();
    });
}

function checkReturnCount() {
    if (recordCount != 0 && recordCount == returnCount) {
        var diff = (new Date).getTime() - start;
        myC.log.push("Loaded " + parent.FirstName + "'s children in " + diff + "ms.");
        $scope.$apply();
    }
}

为了进行比较,请参阅此示例,该示例未使用任何Angular插件(快速): http://plnkr.co/edit/GA17FEnHu7p8wAiDXA5b?p=preview

访问没有AngularFire的孩子的要点

function getChild(childID) {
    recordCount++;
    var tempRef = new Firebase(childrenUrl + childID);
    tempRef.on('value', function (data) {
        myC.children[childID] = data.val();
        returnCount++;
        checkReturnCount();
    });
}

function checkReturnCount() {
    if (recordCount != 0 && recordCount == returnCount) {
        var diff = (new Date).getTime() - start;
        myC.log.push("Loaded " + parent.FirstName + "'s children in " + diff + "ms.");
        $scope.$apply();
    }
}

2 个答案:

答案 0 :(得分:1)

好的,我可能找到了解决方案。显然,Firefox曾经将随机时间添加到它的setTimeouts中,但它不再存在(参见https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)。但是,Firefox(以及其他浏览器)显然仍然具有最小超时延迟(在FF中显然是4ms)。

此页面提出了一个解决方案:http://dbaron.org/log/20100309-faster-timeouts

以下是该博客文章中的setZeroTimeout方法:

// Only add setZeroTimeout to the window object, and hide everything
// else in a closure.
(function() {
    var timeouts = [];
    var messageName = "zero-timeout-message";

    // Like setTimeout, but only takes a function argument.  There's
    // no time argument (always zero) and no arguments (you have to
    // use a closure).
    function setZeroTimeout(fn) {
        timeouts.push(fn);
        window.postMessage(messageName, "*");
    }

    function handleMessage(event) {
        if (event.source == window && event.data == messageName) {
            event.stopPropagation();
            if (timeouts.length > 0) {
                var fn = timeouts.shift();
                fn();
            }
        }
    }

    window.addEventListener("message", handleMessage, true);

    // Add the one thing we want added to the window object.
    window.setZeroTimeout = setZeroTimeout;
})();

当我使用这个setZeroTimeout方法时,使用AngularFire似乎并不比使用基本API慢得多。

为了比较,我使用它而不是$ timeout服务创建了一个新的Plnkr。

这可以包含在AngularFire中吗?或者我现在应该修改我的版本吗?

答案 1 :(得分:1)

好的,我想我已经对上面开始提出的解决方案进行了进一步的改进,这也会根据需要触发角度摘要周期:

我在AngularFire函数中覆盖了_timeout函数,如下所示:

this._timeout = function (fn) {
    fn();
    throttledApply();
};

throttledApply在$ firebase工厂中定义为:

var throttledApply = _.throttle(apply, 100);
function apply() {
    $rootScope.$apply();
}

然后传递给AngularFire函数而不是$ timeout服务。它利用下划线的油门功能立即调用$ apply,然后每100ms调用一次。就我的目的而言,这已足够。它可以很容易地减少到更像50毫秒或25毫秒的东西。

我没有看到这些修改的影响吗?