为什么是 2.0?
Abstract 1.0 去哪了?1.0 就在这里
Abstract 1.0 并非凭空产生,而是来自兴趣部落这样千万级访问量大型项目的最佳实践,经过了千万客户端的检验,也证明了 Abstract 是一款优秀的框架。
Abstract 2.0 是否是轮子?
用过 Abstract 的同学都知道答案是否定的,就拿当下最流行的框架来举例,使用了 AngularJS、React 之后,是否就可以不用 Abstract 了,答案也是否定的,Abstract 解决的问题的层面是高于 AngularJS 和 React 的,在抽象层面上 Abstract 更高于 AngularJS、React。更为简单的叙述是,AngularJS、React 会帮你写业务逻辑么?肯定不会,但 Abstract 会帮你写业务逻辑,这就是 Abstract 和其他框架的区别所在.
如果 React 宣称自己处于抽象层面的 V(view) 层,那么 Abstract 是处于 C(controller) 层的框架
Abstract 为兴趣部落这样大型的项目解决了什么问题?
Abstract 带来的优势是很可观的
- 统一风格的代码
- 清晰的逻辑
- 解决代码复用与耦合的问题
- 快速开发页面
Abstract 怎么去构建页面?
我们来做一个对比,看普通的写法是怎么做的,用 Abstract 是怎么做的
假设我们来完成部落头部的信息的渲染,普通的写法可能是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
var renderTop = function(){ // 请求cgi $.ajax({ url: "/cgi-bin/top_info", data: { bid: 10038 }, success: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } // 渲染模板了 Tmpl(topTmpl, data).appendTo($("#top")); }, error: function(data){ } }); }; renderTop(); |
这么简单的逻辑,感觉写起来还不错
看看使用 Abstract 是怎么做的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var topInfo = new RenderModel({ cgiName: "/cgi-bin/top_info", param: { bid: 10038 }, renderTmpl: topTmpl, renderContainer: $("#top"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); topInfo.rock(); |
哈,感觉没什么高大上的,也没什么吧。。。这还不是 Abstract 强大之处
现在需求来了,产品要求加快 top 渲染的速度,怎么办?有什么办法?
一个办法就是做本地缓存,一进来使用上次请求过的据渲染,安份的写法应该是这样的吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
var renderTop = function(){ //先使用缓存渲染数据 var dataCache = JSON.parse(localStorage.getData("top") || '{}'); Tmpl(topTmpl, dataCache).appendTo($("#top")); // 请求cgi $.ajax({ url: "/cgi-bin/top_info", data: { bid: 10038 }, success: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } // 渲染模板了 Tmpl(topTmpl, data).appendTo($("#top")); //写下缓存供下次使用 // 防止写的时候溢出啊亲 try{ localStorage.setData('top', JSON.stringify(data)); }cache(e){ localStorage.clear(); localStorage.setData('top', JSON.stringify(data)); } }, error: function(data){ } }); } renderTop(); |
看起来也还不错,好像挺好的,这次,第二次之后进来,top 刷刷就出来了,Abstract 怎么写呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Abstract构建的页面 */ var topInfo = new RenderModel({ cgiName: "/cgi-bin/top_info", param: { bid: 10038 }, renderTmpl: topTmpl, renderContainer: $("#top"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); topInfo.rock(); |
看了半天,发现跟之前的写法没什么区别啊?是啊,使用 Abstract 你不需要关心缓存层的渲染的,它自动帮你做了。但有些时候我不需要它做,只需要加上 noCache: false 这样的选项关闭即可
这样感觉也没什么值得炫耀的功能,是的,但是,接定来看
接着我们可能要渲染底部的信息,普通是这么做的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
var renderTop = function(){ //先使用缓存渲染数据 var dataCache = JSON.parse(localStorage.getData("top") || '{}'); Tmpl(topTmpl, dataCache).appendTo($("#top")); // 请求cgi $.ajax({ url: "/cgi-bin/top_info", data: { bid: 10038 }, success: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } // 渲染模板了 Tmpl(topTmpl, data).appendTo($("#top")); //写下缓存供下次使用 // 防止写的时候溢出啊亲 try{ localStorage.setData('top', JSON.stringify(data)); }cache(e){ localStorage.clear(); localStorage.setData('top', JSON.stringify(data)); } }, error: function(data){ } }); }; var renderBottom = function(){ //先使用缓存渲染数据 var dataCache = JSON.parse(localStorage.getData("bottom") || '{}'); Tmpl(topTmpl, dataCache).appendTo($("#bottom")); // 请求cgi $.ajax({ url: "/cgi-bin/bottom_info", data: { bid: 10038 }, success: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } // 渲染模板了 Tmpl(bottomTmpl, data).appendTo($("#bottom")); //写下缓存供下次使用 // 防止写的时候溢出啊亲 try{ localStorage.setData('bottom', JSON.stringify(data)); }cache(e){ localStorage.clear(); localStorage.setData('bottom', JSON.stringify(data)); } }, error: function(data){ } }); }; renderTop(); renderBottom(); |
这样写或许也挺简单的,但是不同的人有不同的写法,可能一个 renderTop 和一个 renderBottom 写法就不同,更别说更加复杂的逻辑,那 Abstract 怎么写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/* Abstract构建的页面 */ var topInfo = new RenderModel({ cgiName: "/cgi-bin/top_info", param: { bid: 10038 }, renderTmpl: topTmpl, renderContainer: $("#top"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); var bottomInfo = new RenderModel({ cgiName: "/cgi-bin/bottom_info", param: { bid: 10038 }, renderTmpl: bottomTmpl, renderContainer: $("#bottom"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); var page = new PageMode(); page.add(topInfo); page.add(bottomInfo); page.rock(); |
细心的同学会发现,Abstract 在最后,不是让 topInfo 和 bottomInfo 分别 rock,而上加到了一个 pageModel 的实例上,让 pageModel 实例去 rock。
可以看出,Abstract 的优点
1. 规范化代码,所有人的代码风格统一,阅读方便
2. 写法简单,快速
3. 尽可能多的帮业务开发者做更多的事情
4. 页面模块化的思想与配置型代码(类似 React,但那时不了解有 React)
5. 更优雅的代码
上面的例子还不足矣让 Abstract 来支撑更复杂的页面,那如果更复杂页面怎么写?
移动中比较常见的场景就是滚动加载,这时用 Abstract 要怎么写呢?
普通的写法,可能要洋洋洒洒写上一大篇了吧,Abstract 是这样写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/* Abstract构建的页面 */ var topInfo = new RenderModel({ cgiName: "/cgi-bin/top_info", param: { bid: 10038 }, renderTmpl: topTmpl, renderContainer: $("#top"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); var bottomInfo = new RenderModel({ cgiName: "/cgi-bin/bottom_info", param: { bid: 10038 }, renderTmpl: bottomTmpl, renderContainer: $("#bottom"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); // 这里是一个滚动加载模型 var postList = new ScrollModel({ cgiName: "/cgi-bin/posts", param: function(){ var every = 10; var start = - every; return function(){ return { start: start += every, num: every, bid: 10038 }; }; }(), renderTmpl: postTmpl, renderContainer: $("#postList"), processData: function(data){ for(var i = 0; i < data.posts.length; i ++){ var item = data.posts[i]; item.flag = getFlag(item.flag); } } }); var page = new PageMode(); page.add(topInfo); page.add(bottomInfo); page.add(postList); page.rock(); |
就这么简单,一个简单的页面就完成了
欧俊杰 2015 年 9 月 2 日
有中文的学习资料吗?
asdf 2015 年 8 月 30 日
df
dashi 2015 年 8 月 22 日
楼主的思想是类似 backbone 的 MVC 么?一个页面分多个模块,一个模块对应一个 (ajax) 接口 (鹅厂习惯叫 cgi),但是问题来了:比如一个显示商品详情的小模块 (cgiName=detail) 在线上跑了很久了,突然一天,产品说在这块里面加个按钮吧,按钮的显示逻辑需要满足某些条件,于是,后台增加了一个后台接口 (cgiName=show_btn) 来判定按钮的显示逻辑,abstract 里这种 cgi<=>model 的模型怎么满足这种情况?后来,产品又加了需求,是会员的话在 A、C、F 三个模块下加一些信息,这时后台又多了个接口… 再后来,接口越来越多,页面越来越复杂… 期待楼主解答。
dorsy 2015 年 8 月 24 日
首先,一个页面模块对应不是一个 cgi 接口,一个页面模块对应是一块区域的渲染,跟 cgi 接口无关的。也就是说,一条 cgi 可以提供给多个模块渲染,一个模块也可以拥有多个 cgi。数据 与 模块渲染 是分离的,cgi 只是提供数据的源,与模块无关举个例子: 一条 cgi 可能为多个页面模块提供数据,那么 Abstract.js 中的实现 var top = new RenderModel({ cgiName: “get_more_info”});var main = new RenderModel();// top 的数据将会被 main 使用 top.feed(main); 后面问题的只说一种解决方案:1. 增加的信息能否与其他 cgi 合并,尽量减少 cgi 请求次数 比如: 会员信息就可以与页面的一些信息进行合并返回 2. cgi 接口是否真的与渲染有关? 有些 cgi 接口可能仅仅是与渲染无关的,只放在事件中去单独处理 3. cgi 与渲染有关,在 cgi 没出发前就定义模块,根据 cgi 返回进行动态的添加与 rock 总的来说:1. 减少 cgi 请求,合并 cgi2. 与页面渲染块对应 3. 预先定义模块,不要在模块中动态定义模块,而是在模块中动态调用模块这样会让页面始终保持松散与清晰希望能回答你的问题
TAT.dorsywang 2015 年 8 月 24 日
首先,一个页面模块对应不是一个 cgi 接口,一个页面模块对应是一块区域的渲染,跟 cgi 接口无关的。也就是说,一条 cgi 可以提供给多个模块渲染,一个模块也可以拥有多个 cgi。数据 与 模块渲染 是分离的,cgi 只是提供数据的源,与模块无关举个例子: 一条 cgi 可能为多个页面模块提供数据,那么 Abstract.js 中的实现 var top = new RenderModel({ cgiName: “get_more_info”});var main = new RenderModel();// top 的数据将会被 main 使用 top.feed(main); 后面问题的只说一种解决方案:1. 增加的信息能否与其他 cgi 合并,尽量减少 cgi 请求次数 比如: 会员信息就可以与页面的一些信息进行合并返回 2. cgi 接口是否真的与渲染有关? 有些 cgi 接口可能仅仅是与渲染无关的,只放在事件中去单独处理 3. cgi 与渲染有关,在 cgi 没出发前就定义模块,根据 cgi 返回进行动态的添加与 rock 总的来说:1. 减少 cgi 请求,合并 cgi2. 与页面渲染块对应 3. 预先定义模块,不要在模块中动态定义模块,而是在模块中动态调用模块这样会让页面始终保持松散与清晰希望能回答你的问题