FirebaseExtended / angularfire

AngularJS bindings for Firebase

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Angularfire 2.3.0 incompatible with firebase 3.7.1

javoire opened this issue · comments

Version info

Angular:
1.6.1

Firebase:
3.7.1

AngularFire:
2.3.0

Other (e.g. Node, browser, operating system) (if applicable):
Chrome Version 56.0.2924.87 (64-bit)

Test case

https://plnkr.co/edit/kKHCbTgqVicuHUAHwigr?p=preview

Steps to reproduce

  1. Input your firebase credentials
  2. (optionally) set your DB rules to allow read/write anonymously for test purposes
  3. when the plunkr runs, the window should freeze.

Pausing the execution in dev tools will show you an infinite async loop that I'm describing at the end of this report.

Expected behavior

not freezing

Actual behavior

freezing

Some debugging info

When using 3.6.6 and stepping into the $add function. We can see that the firebase reference looks like this:

ref: U
  Nc: false
  catch: undefined
  database: (...)
  key: (...)
  m: ee
  parent: (...)
  path: L
  ref: (...)
  root: (...)
  then: undefined
  u: Te
  __proto__: X

When using 3.7.1 and stepping into the $add function. We can see that the firebase reference looks like this:

ref: T
  Nc: false
  catch: ()
  database: (...)
  key: (...)
  m: lg
  parent: (...)
  path: L
  ref: (...)
  root: (...)
  then: ()
  u: Sd
  __proto__: Y

Wee se that catch and then are functions. Which seems to lead to an endless async loop in angular ($q). Where the recursive function $$resolve keeps calling itself, from here:
https://github.com/angular/angular.js/blob/03043839d5a540b02208001fe12e812dfde00a8e/src/ng/q.js#L426
and here:
https://github.com/angular/angular.js/blob/03043839d5a540b02208001fe12e812dfde00a8e/src/ng/q.js#L439
because this:
https://github.com/angular/angular.js/blob/03043839d5a540b02208001fe12e812dfde00a8e/src/ng/q.js#L424
keeps being true

That's as far as I got :) I don't understand how or why this is happening, but I believe I have pinned down where it happens and I'm able to reproduce it.

I haven't found any other reports of this so I hope I'm not reposting :)

AngularFire 2.3.0 still causes browser freeze with $firebaseArray.$add on Firebase 3.7.2 + Angular 1.6.3

Same here with Angular 1.5.11 + Firebase 3.7.2 + AngularFire 2.3!

Thanks for the bug report! This does in fact look like a pretty nasty issue. I am not sure what changed to caused this behavior, but we will track it down. I was able to get your code to work with 3.7.0 but cause the hang in 3.7.1, so that is where we will focus our efforts.

Note that your code is technically not correct (even in the older Firebase versions that don't hang). You are trying to call $add() on a $firebaseArray instance which is not yet initialized. This won't behave in the way you expect. Instead of:

angular.module('app', ['firebase'])
  .controller('Ctrl', function($scope, $firebaseArray) {
    const list = $firebaseArray(firebase.database().ref());
    const data = {
      thing: 1,
    };
    list.$add(data);
  });

You should either wait to call $add() until the array is fully loaded:

angular.module('app', ['firebase'])
  .controller('Ctrl', function($scope, $firebaseArray) {
    const list = $firebaseArray(firebase.database().ref());
    list.$loaded()
      .then(() => {
        const data =  {
          thing: 1,
        };
        return list.$add(data);
    })
    .then(() => {
      console.log("Success!");
    })
    .catch((error) => {
      console.log("Error:", error);
    }
  });

Or, even better, wait to call $add() until some action is taken:

angular.module('app', ['firebase'])
  .controller('Ctrl', function($scope, $firebaseArray) {
    const list = $firebaseArray(firebase.database().ref());
    
    $scope.addItem = (item) => {
      const data = {
        thing: 1,
      };
      list.$add(data);
    };
  });

Assigning this over to @jshcrowthe to investigate the hang further, since we will definitely want to understand why this is happening and how we can fix it.

@jwngr Ah, good point! Anyways, looking forward to getting to know the root cause of this :)

@jshcrowthe and I have tracked down the underlying issue which was a recent change in the Firebase SDK which was introduced in 3.7.1. I was able to create the following repro which shows the issue without AngularFire at all:

var firebase = require("firebase");

var config = {
  databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
};

firebase.initializeApp(config);

var ref1 = firebase.database().ref("messages").push();
var ref2 = firebase.database().ref("messages").push("foo");

/*
ref1
  .then(function() {
    console.log("[ref1] All done!");
  })
  .catch(function(error) {
    console.log("[ref1] Error:", error);
  });
*/

ref2
  .then(function() {
    console.log("[ref2] All done!");
  })
  .catch(function(error) {
    console.log("[ref2] Error:", error);
  });

This script runs successfully as is (after you replace <DATABASE_NAME>) and outputs "[ref2] All done!". But if you uncomment the commented out block of code, the script will hang and not output anything. The problem is a recent change to push() when it does not contain a value. That returns a ThenableReference which is fulfilled with another ThenableReference, instead of a regular Reference, triggering an infinite loop of promise fulfillment. AngularFire runs into this issue on these lines.

We are putting together a fix which we will get out as soon as we can.

After a lot of my app users complaining about chrome freezing when adding some entities I realized that downgrading from 3.7.1 to 3.7.0 solves this issue. I think this is the same problem that you found on 3.7.1 release. Thank you for your support.

@lmadeira this issue was introduced in the change from 3.7.0 to 3.7.1 so you are correct. We have a fix in place which will go out with our next release.

Thanks everyone for your help!

Firebase 3.7.4 was just released that contains a fix for this issue! (See full release notes here: https://firebase.google.com/support/release-notes/js#3.7.4)

I have updated your plunk (https://plnkr.co/edit/HVu3tAVg1kMpNvYOGb3B?p=preview) and things seem to be working as intended.

For clarity's sake an isolate example of the issue (no angular/angularfire) can be found here: http://jsbin.com/habeyed/9/edit?html,console

Thanks for your patience and let us know if there are any further issues.

Very happy to find this! Thank you very much!

Awesome! Thanks for this fix!