Benjamin Gruenbaum Benjamin Gruenbaum - 3 months ago 50
AngularJS Question

How do I use Bluebird with Angular?

I tried using Angular with Bluebird promises:

HTML:

<body ng-app="HelloApp">
<div ng-controller="HomeController">{{name}} {{also}}</div>
</body>


JS:

// javascript
var app = angular.module('HelloApp', []);

app.controller("HomeController", function ($scope) {
var p = Promise.delay(1000).then(function () {
$scope.name = "Bluebird!";
console.log("Here!", $scope.name);
}).then(function () {
$scope.also = "Promises";
});
$scope.name = "$q";
$scope.also = "promises";
});

window.app = app;


[Fiddle]

However, no matter what I tried, it kept staying
"$q promises"
and did not update. Except if I added a manual
$scope.$apply
which I'd rather avoid.

How do I get Bluebird to work with AngularJS?



(I know it's possible since $q does it)

I'm using Bluebird 2.0 which I got here.

Answer

This is possible, and even quite easy!

Well, if we look at how Angular's own promises work, we need to get Bluebird to $evalAsync somewhere in order to get the exact same behavior.

If we do that, the fact both implementations are Promises/A+ compliant means we can interop between $q code and Bluebird code, meaning we can use all of Bluebird's features in Angular code freely.

Bluebird exposes this functionality, with its Promise.setScheduler functionality:

// after this, all promises will cause digests like $q promises.
function trackDigests(app) {
    app.run(["$rootScope",function ($rootScope) {
        Promise.setScheduler(function (cb) {
            $rootScope.$evalAsync(cb);
        });
    }]);
}

Now all we have to do is add a:

trackDigests(app); 

line after the var app = ... line, and everything will work as expected. For bonus points, put Bluebird in a service so you can inject it rather than use it on the global namespace.

Here is a [Fiddle] illustrating this behavior.

Note that besides all the features Bluebird has over $q, one of the more important ones is that Bluebird will not run $exceptionHandler, but instead will automatically track unhandled rejections, so you can throw freely with Bluebird promises and Bluebird will figure them out. Moreover calling Promise.longStackTraces() can help with debugging a lot.