0

I'm using LocalForage library to have offline data in my web app.

I have a separate service to get and set values to indexed db.The service as follows,

var service = angular.module("DBService",[]);

service.factory('$dbService', function($q){
// Configuration
drivers = [localforage.INDEXEDDB, localforage.LOCALSTORAGE];
localforage.config({
    driver: drivers,
    name:"Cars"
});
localforage.setDriver(localforage.INDEXEDDB);
//
var _set = function(key_,value_){
    //
    var defered = $q.defer();
    localforage.setItem(key_, value_).then(
        function(data){
            //
            defered.resolve(data);
        }
    );
    return defered.promise;
};
var _get = function(key_){
    var defered = $q.defer();
    localforage.getItem(key_).then(
        function(data){
            //
            defered.resolve(data);
        }
    );
    return defered.promise; 
};

return {
    _set: _set,
    _get: _get
}

});

Following is the view,

<html ng-app="App">
<head>
<script src="angular.min.js"></script>
<script src="localforage.js"></script>
<script src="service.js"></script>
<script src="main.js"></script>
<title>Angular App</title>
</head>
<body>
<div ng-controller="DatabaseController" id="main" ng-init="pageInit()">
    <button ng-click="saveAsync(4)">click</button>
    <button ng-click="saveAsync2(5)">click</button>
</div>
</body>
</html>

Following is the controller,

var app = angular.module("App",['DBService']);

app.controller('DatabaseController', function($scope, $dbService){
//
$scope.pageInit = function(){
    //
    var initialize = [1,2,3];
    $dbService._set('List', initialize).then(
        function(data){
            //
            console.log("init : " + JSON.stringify(data));
        }
    );
};
//
$scope.$saveAsync = function(value_){
    //
    $dbService._get('List').then(
        function(data){
            //
            console.log("async operation : " + JSON.stringify(data));
            var tempList = data;
            tempList.push(value_);  
            $dbService._set('List',tempList).then(
                function(data){
                    //
                    console.log("async operation resolved : " +  data);
                }
            );
        }
    );
};
//
$scope.saveAsync = function(value_){
    //
    $scope.$saveAsync(value_);
};
//
$scope.saveAsync2 = function(value_){
    //
    $scope.$saveAsync(value_);
};
//
setInterval(function() {
    $scope.$saveAsync(6);
    $scope.$saveAsync(7);
}, 1000);
});

The problem occurs at the setInterval as it will call $scope.$saveAsync() method twice with different parameters. But at the point of resolving the both promises they only contains the initial value which is 1,2,3 according to this scenario. so the program will set 1,2,3,6 in the first $scope.$saveAsync() method call and 1,2,3,7 in the second $scope.$saveAsync() method call. Finally only 1,2,3,7 will be get saved in indexeddb the value 6 is missed.

having a $q.all resolves this problem. but it is only applicable within the setInterval scope. As the user can have read write actions to the same data at the point of setInterval also running pointing to the same data.

Likewise The problem occurs when i tries to get a particular key value for a several times simultaneously and tries to update that key's values. Because calling to the method get() some times returns an old data set as the get calls will be asynchronous. so when the set method is invoked at an old data set there is a data loose within the indexed db.

Thanks in advice.

  • I'm afraid it's not at all clear what you're asking. You're currently waiting for the `get` to complete before calling `set`, so...? Please update your question with a [mcve] demonstrating the problem, ideally making it **runnable** by using Stack Snippets (the `[<>]` toolbar button). You can't use local storage in snippets, sadly, but your question isn't really about storage anyway, it's about how to handle asynchronous behavior. So you should be able to strip it down to a runnable example using JavaScript's native promises. – T.J. Crowder Sep 04 '17 at 10:38
  • See also [this answer](https://stackoverflow.com/a/43766002/157247) (and some of the other answers to that question generally), which goes into detail about handling multiple asynchronous requests either in parallel or in series, with promises and without. – T.J. Crowder Sep 04 '17 at 10:48
  • in `CallAPI` you're not waiting for the `set()` to complete before you return a result. And in `$scope.callloop()` you're not checking at all that the previous `CallAPI` call has finished. – Thomas Sep 04 '17 at 12:13

0 Answers0