Question

I guess I don't believe in myself as a good programmer but I found out this method on my own (not suggestion I'm the first one to do it, but I didn't follow a guide) so it must be broken somehow.

$q is mainly a callback kind of service for async reasons, but it served me in another way as well.

I might have multiple calls to a long running service, but I only need a response once. So I want to disregard all calls except from the first one and cache the result from that and return to everybody.

If I give everybody a promise when called they get the result when the promise is resolved, even if it was resolved before the promise was actually given, that's a nice feature.

So I could only make the dervice call the first time I give the promise.

myApp.factory('serviceWithLongCall', function ($q, $timeout) {

    var data = {}
    var hasStarted = false;
    var deferred = $q.defer();

    return {
        call: call
    };

    function call() {
        if (!hasStarted) {
            hasStarted = true;
            console.log('timeout started');
            $timeout(function () {
                console.log('timeout ended');
                data = 42;
                deferred.resolve(data);
            }, 3000);
        }

        return deferred.promise;
    }

});

fiddle with example, click some buttons and wait for 3 seconds from first click, later clicks will happen instantly.

Is something off with this method, will I have a race condition?

Was it helpful?

Solution

Returning the same promise from a call multiple times for caching reasons is absolutely fine. No race condition that I can think of, and I've used that technique with no issue.

The only small issue with you code is that's it's unnecessary to create the deferred object. $timeout returns a promise that can resolve to the value you want.

myApp.factory('serviceWithLongCall', function ($timeout) {

    var data = {}
    var promise = null;

    return {
        call: call
    };

    function call() {
        if (!promise) {
            console.log('timeout started');
            promise = $timeout(function () {
                console.log('timeout ended');
                data = 42;
                return data;
            }, 3000);
        }

        return promise;
    }
});

Admittedly your use of $timeout might be just for example reasons, but I suspect you can do the same thing with $http.

Licensed under: CC-BY-SA with attribution
scroll top