AngularJS承诺正在缓存

AngularJS promise is caching

本文关键字:缓存 承诺 AngularJS      更新时间:2023-09-26

我想我的承诺写错了,我不明白它为什么要缓存数据。结果是,假设我以scott的身份登录。当应用程序启动时,它将连接到一个端点以获取设备名称和设备映射的列表。它目前运行良好。

当我注销而不刷新浏览器时,我以不同的用户身份登录,斯科特在同一浏览器选项卡上检索到的设备名称,会被新登录的用户看到。然而,我可以从Chrome的网络选项卡中看到,端点被调用,它收到了正确的设备名称列表。

因此,我考虑在工厂中添加destroyDeviceListing函数,希望能够清除这些值。此函数在注销过程中被调用。然而,这并没有起到任何作用。下面是我的工厂

app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
    var deferredLoad = $q.defer();
    var isLoaded = deferredLoad.promise;
    var _deviceCollection = { deviceIds : undefined };
    isLoaded.then(function(data) {
        _deviceCollection.deviceIds = data;
        return _deviceCollection;
    });
    return {
        destroyDeviceListing : function() {
            _deviceCollection.deviceIds = undefined;
            deferredLoad.resolve(_deviceCollection.deviceIds);
        },
        getDeviceIdListing : function() {
            return isLoaded;
        },
        getDeviceIdMapping : function(deviceIdsEndpoint) {
            var deferred = $q.defer();
            var userData = User.getUserData();
            // REST endpoint call using Restangular library
            RestAPI.setBaseUrl(deviceIdsEndpoint);
            RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
            RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
                .then(function(res) {
                    _deviceCollection.deviceIds = _.chain(res)
                        .filter(function(data) {
                            return data.devPrefix != 'iphone'
                        })
                        .map(function(item) {
                            return {
                                devPrefix : item.devPrefix,
                                name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
                            }
                        })
                        .value();
                    deferredLoad.resolve(_deviceCollection.deviceIds);
                    var deviceIdMapping = _.chain(_deviceCollection.deviceIds)
                        .groupBy('deviceId')
                        .value();
                    deferred.resolve(deviceIdMapping);
                });
            return deferred.promise;
        }
    }
}])

下面是我的控制器的摘录,缩短和清洁版本

.controller('DeviceController', ['DeviceFactory'], function(DeviceFactory) {
     var deviceIdMappingLoader = DeviceFactory.getDeviceIdMapping('http://10.5.1.7/v1');
     deviceIdMappingLoader.then(function(res) {
        $scope.deviceIdMapping = res;
        var deviceIdListingLoader = DeviceFactory.getDeviceIdListing();
        deviceIdListingLoader.then(function(data) {
            $scope.deviceIDCollection = data;
        })
    })
})

好吧,整个应用程序只有一个var deferredLoad。由于promise只代表一个异步结果,因此延迟的结果也只能解析一次。您需要为每个请求创建一个新的deferred——尽管您根本不需要创建一个deferred,但您可以使用现有的promise。

如果不需要任何缓存,则模块中不应该有全局deferredLoadisLoaded_deviceCollection变量。只做

app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
    function getDevices(deviceIdsEndpoint) {
        var userData = User.getUserData();
        // REST endpoint call using Restangular library
        RestAPI.setBaseUrl(deviceIdsEndpoint);
        RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
        return RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
        .then(function(res) {
            return _.chain(res)
            .filter(function(data) {
                return data.devPrefix != 'iphone'
            })
            .map(function(item) {
                return {
                    devPrefix : item.devPrefix,
                    name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
                };
            })
            .value();
        });
    }
    return {
        destroyDeviceListing : function() {
            // no caching - nothing there to be destroyed
        },
        getDeviceIdListing : function(deviceIdsEndpoint) {
            return getDevices(deviceIdsEndpoint)
            .then(function(data) {
                return { deviceIds: data };
            });
        },
        getDeviceIdMapping : function(deviceIdsEndpoint) {
            return this.getDeviceIdListing(deviceIdsEndpoint)
            .then(function(deviceIds) {
                return _.chain(deviceIds)
                .groupBy('deviceId')
                .value();
            });
        }
    };
}])

现在,要添加缓存,只需创建一个全局promise变量,并在创建请求后将promise存储在那里:

var deviceCollectionPromise = null;
…
return {
    destroyDeviceListing : function() {
        // if nothing is cached:
        if (!deviceCollectionPromise) return;
        // the collection that is stored (or still fetched!)
        deviceCollectionPromise.then(function(collection) {
            // …is invalidated. Notice that mutating the result of a promise
            // is a bad idea in general, but might be necessary here:
            collection.deviceIds = undefined;
        });
        // empty the cache:
        deviceCollectionPromise = null;
    },
    getDeviceIdListing : function(deviceIdsEndpoint) {
        if (!deviceCollectionPromise)
            deviceCollectionPromise = getDevices(deviceIdsEndpoint)
            .then(function(data) {
                return { deviceIds: data };
            });
        return deviceCollectionPromise;
    },
    …
};