自去年开始,AngularJS 引入到项目中,并逐渐推进公司产品核心模块进行重构,提高产品稳定性与开发效率。在前端架构演进的过程当中最艰难的不是理解 API,而是思惟方式被颠覆的无助,全部繁杂的事务都被高度抽象化,之前 WEB 富 UI 开发最头疼的表现部分放到如今几乎不费吹灰之力,前端工程师重心将由 UI 转向数据模型的构建。在这个过程当中,小伙伴常常会遇到跨页数据传递这个经典问题,因而我在公司给组里同事作了一次分享,如下是概要:前端
使用同一个控制器与同一份实例,不使用路由浏览器
缺点缓存
经过 URL 查询参数传递数据安全
缺点前端工程师
String
类型)使用 Angular Service 构建内存缓存闭包
权衡后,采用此方案。架构
// 取 URL 的 cache key var cacheKey = $routeParams['cache_key'];
读写缓存优化
if (!AppCache.cache || AppCache.key !== cacheKey) { // 覆盖 service 缓存 AppCache.cache = createCache(); AppCache.key = cacheKey || Date.now().toString(); }
发送缓存spa
// 经过路由传递缓存 $scope.submit = function () { var queryParam = angular.extend({ 'cache_key': AppCache.key }, $routeParams); $location.search(queryParam); }
$routeChangeSuccess
事件中清理缓存清理过时缓存prototype
$rootScope.$on('$routeChangeSuccess', function () { if ($routeParams['cache_key'] === undefined) { AppCache.cache = {}; } })
高度抽象,屏蔽实现细节
// 读缓存 var routeCache = RouteCache(createCache); var data = routeCache.getCache(); var cacheKey = routeCache.getKey(); // 经过路由传递缓存 $scope.submit = function () { var queryParam = angular.extend({ 'cache_key': cacheKey }, $routeParams); $location.search(queryParam); }
// 读缓存 var data = RouteCache(createCache); // 经过路由传递缓存 $scope.submit = function () { var queryParam = angular .extend({}, data, $routeParams); $location.search(queryParam); }
问题:如何作到 URL 只显示 cache_key 而不暴露数据?
答案:使用原型继承,angular.extend 不会拷贝原型。
RouteCache 内部:
data = createCache(); data = Object.create(data); data['cache_key'] = cacheKey;
Object.create(data)
是 ECMA5 增长的方法,原理相似:
Object.create = function (object) { function F(){}; F.prototype = object; return new F(); }
/* * 基于路由的缓存服务 * 能够将任何数据模型缓存在路由参数中,适合处理跨页的数据传递 * * 取缓存: * $scope.data = RouteCache(cacheFactory); * 写缓存: * $location.search( * angular.extend( * {}, * $routeParams, * $scope.data * ) * ); * * @author 糖饼 */ define(['./services'], function (services) { services.factory('RouteCache', ['$rootScope', '$routeParams', '$cacheFactory', function ($rootScope, $routeParams, $cacheFactory) { var cache = $cacheFactory('RouteCache'); var ROUTE_KEY = '@cache_key'; var TABLE_NAME = 'CACHE'; /* * @param {Function} 缓存工厂 * @return {Object} 继承自缓存的对象 */ function Cache (cacheFactory) { var data = cache.get(TABLE_NAME); var routeKey = $routeParams[ROUTE_KEY]; if (!data || cache.get(ROUTE_KEY) !== routeKey) { data = cacheFactory(); // 继承缓存 data = Object.create(data); cache.put(TABLE_NAME, data); cache.put(ROUTE_KEY, routeKey || Date.now().toString()); } data[ROUTE_KEY] = cache.get(ROUTE_KEY); return data; }; // 自动清理缓存 $rootScope.$on('$routeChangeSuccess', function () { if (typeof $routeParams[ROUTE_KEY] === 'undefined') { cache.removeAll(); } }); return Cache; }]); });