自去年開始,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; }]); });