【问题标题】:Why is AngularFire so much slower than plain Firebase API为什么 AngularFire 比普通的 Firebase API 慢得多
【发布时间】:2014-02-20 07:36:45
【问题描述】:

在使用 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();
    }
}

【问题讨论】:

  • AngularFire 似乎慢了大约 3 倍。我在 Firefox 26 上看到了这些数字——AngularFire Parent 1 用了 973ms,Parent 2 用了 491ms,Parent 3 用了 641ms;与普通 Firebase 父级 1 的 289 毫秒,父级 2 的 146 毫秒,父级 3 的 169 毫秒。这与您的测试相符吗?
  • 类似,是的。它因页面加载而异,但 AngularFire 始终慢约 3 倍。
  • 这似乎可能来自将事物放入 $compile 阶段所需的 $timeout 调用以及 $compile 本身,两者都使用延迟回调,这也解释了 Firefox 中解释 setTimout 为零的差异20 - 150 毫秒
  • 好的。 AngularFire 库是否有理由不使用承诺?或者是吗?我基本上是在使用 Promise 编写自己的版本,并且没有库所做的滞后。

标签: performance firebase angularfire


【解决方案1】:

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

本页提出解决方案: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 中吗?还是我现在应该修改我的版本?

【讨论】:

  • 至少在没有进一步修改的情况下,上面的代码似乎没有记录 Angular 摘要循环的变化(我没有很好地掌握)。有关如何执行此操作的任何建议?
  • 所以,如果我了解 AngularFire 的工作原理,它只是在运行后使用 $timeout 来触发摘要循环。因此,当您最初加载 400 个子节点时,速度变慢是由于两件事:1. 浏览器最小超时延迟(在某些浏览器中为 4 毫秒),以及 2. 为每个子节点调用 $rootScope.$apply()。不能完全取消 $timeout,只需在“加载”时调用 $rootScope.$apply() 一次,然后为每个 child_added/child_changed 调用一次?
【解决方案2】:

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

我重写了AngularFire函数中的_timeout函数如下:

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

throttledApply 在 $firebase 工厂中定义为:

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

然后传递给 AngularFire 函数而不是 $timeout 服务。它利用下划线的节流函数立即调用 $apply,然后最多每 100 毫秒调用一次。就我的目的而言,这就足够了。它可以很容易地减少到更接近 50 毫秒或 25 毫秒的时间。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-02
    • 2012-07-29
    • 2016-02-13
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 2017-12-26
    相关资源
    最近更新 更多