您的位置:首页 > 其它

模版+数据分离渲染方式的设计与实现

2013-09-25 22:14 417 查看
一 背景

1 现状

模版存放于后端

php输出页面html结构进行页面渲染

ajax请求,需要重渲结构时,php输出html结构

builder制作静态页面结构

jser完成页面交互逻辑开发

2 不足

模版数据无法存储本地,导致每次打开页面请求数据量巨大

数据每次要从接入层web服务器读取,没有合理利用CDN加速静态模版内容

联调成本较大,不利于前端控制页面展示和交互开发

3 解决方案

后端直接输出json数据

试图把渲染页面的模版存放在前端

4 技术路线





5 理论意义

利用CDN保存html模版,看起来第一次请求会使用多一点的资源,实际上消耗并不是很大,且多次请求可以减小下载量

充分利用缓存,提高性能

联调成本大大降低,后端只需要按规则输出Json数据,前端能更大程度的控制页面展示,减小bug量

二 基于模版与数据分离渲染方式的方案设计

1 ejs模版简介

官方API地址:http://www.embeddedjs.com/

官方API介绍的很清楚,也是大多数模版的常用办法。下面列举几个特殊用法:

可自定义函数





支持常用html标签的快捷方式,就像ruby on rails framework的做法一样,让代码更简洁。

支持模版错误提示





另外,ejs支持nodejs

2 pageletView渲染组件简介

pageletView按照页面的模块分别输出模块id,css,js,html





3 ejs与pageletView的融合方案设计

pageView在渲染页面的时候,是分模块进行渲染的。这种方式是实现bigpipe的重要渲染方式,那么需要我们在不改变原有pageview的基础上进行改造。

即在原有的技术上,多传给STK.pageletM.view方法参数的两个属性,一个属性命名为data,用来存放json数据传递给前端使用,另一个属性命名为template,用来存放模块的模版文件。





然而,由于页面上有多少个模块,就会有多少个template文件,在实现完成这种渲染之后,发现如果一个页面上的模块比较多的话,就会给页面渲染带来一定的负担,所以决定把一个页面的模版合并成一个模版文件,这样只需要请求一次模版文件就可以了。设计如下:





三 基于模版与数据分离渲染方式的实现

1模版的传递办法

ejs拿到模版和数据后,执行渲染。数据可以在pageLet拿到数据的时候,通过参数传递,而每个模块的渲染,需要动态的传递模块template,不可能直接$Import写死到ejs文件,也不可能$Import写死到pageletView文件里。这个问题有两种办法解决。

把模版设置成全局变量

使用listener广播事件监听

显然,第一种把模版设置成全局变量的办法有很大风险,容易造成混淆和错乱,切不利于维护。于是我们选择第二种办法,listener事件广播的形式。因为第二种办法,在需要使用到模版的地方,我们通过架设管道的方式,一对一的监听模版发出的广播,从ejs模版里进行接收,这样就避免了抛到全局造成的问题。

2 实现无等待的模版渲染

然而,在使用listener事件的时候又遇到了问题。

因为熟悉listener事件的同学都知道,事件fire与事件register是有先后顺序的,register在前,fire在后,也就是说在ejs需要使用模版的时候,我们会使用listener的register方法绑定事件,然后才可以把模版fire出来,那么我们很容易想到把合并完的模版文件a.js放在pageletView渲染模块之后,但是放在后面我们是无法监听到对应模块的pageletView已经register完成的,这时候如果使用setTimeout的方式虽然能够解决问题但是存在着很大的弊端,因为第一,setTimeout需要耗费性能,渲染出页面的体验非常差,第二,我们做了个测试,如果setTimeout的时间参数小于1000ms的话,成功渲染所有模块只能成为偶发的事情。

怎么解决这个问题呢,我们最后想到了一个办法,使用两个广播进行解决。

首先,我们把模版合并好的a.js文件放在pageletM(pageletM会调用pageletView方法)渲染之前,register一个广播,广播的名字叫做id+’_temp’,在这个广播里我们去把模版fire出去,fire的参数为id。





其次,我们在ejs文件里register一个事件,这个参数为模块的id(即pid),然后fire一个事件,fire的参数为id+’_temp’





整个传递的步骤为:

首先ejs文件监听模版文件,然后模版文件fire出模版,整个目的就达到了。

这个过程描述如图:

说明:首先页面加载模版文件,模版文件监听pageletView文件reday的listener事件,回调函数fire出“模版”,然后页面运行pageletView文件,pageletView文件注册了模版文件ready的事件,然后再pageView文件里发出模版pagelet已经ready的信号。这样在pageletView执行的时候,模版告诉pageletView模版已经ready,监听过模板ready的回调函数就可以收到模版从而完成模板与数据拼接了。这样就实现了无等待的数据加模版渲染。





3 pageletView中的向下兼容

由于微博现如今使用的方式是模版放在后端进行,前端取到后端传出的html,然后进行渲染,若使用template+data的方式进行页面渲染,我们可以做一下向下兼容。如下图,判断若data != undefined则通过template+data进行渲染,否则使用原有的方式进行渲染。





4 实现trans请求的模版渲染

大家知道,前端对后端ajax请求成功的时候,若前端需要改变某个节点的innerHTML,后端会返回一段html代码,而当我们点击feed分页的时候,可能会浪费大量的模版流量,如果把模版存在前端,后端只需要提供每个feed需要的数据就可以了,这个可以节省很多资源。

实现这种方式很简单,只需要按照pageletView中的使用方式就可以了,但是这样的话会存在一个问题。前端拿到模版和数据拼接好html结构后,需要知道怎么去处理这段html,所以我们把insertHTML集成在ejs中,通过传递参数的形式,去让ejs执行innerHTML或者是insertHTML(如下图)。





5 实现ejs文件的简单使用

每次使用可能我们都需要注册一个事件,并在这个事件内抛出另一个事件,使用起来非常不方便。经过分析与设计,我们决定把模版中的注册事件和fire事件封装起来,调用的过程中只需要传递几个参数就可以实现效果。如下图:

模版文件引用sedEjsTemplate.js,业务文件引用$.kit.dom.ejs文件(pageletView对$.kit.ejs的引用是一种特例)。









6 template+data使用步骤(非常简单好用)

第一步:写模版文件。





第二步:使用$.kit.dom.ejs();





参数说明:



转载自:http://weiboria.sinaapp.com/?p=45
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: