ltemplate.lua
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
|
local insert = table.insert local remove = table.remove local concat = table.concat local format = string.format local loaded = {} local partten = "(.-){#([^#].-[^#])#}()" local content = {} local cur_content = nil local function ob_start() cur_content = {} insert(content, cur_content) end local function ob_get_clean() local ret = concat(cur_content) remove(content) cur_content = content[#content] return ret end local function echo(value) insert(cur_content, value) end local function include(path, params) local bitcode = loaded[path] if not bitcode then local fp = io.open(path, "rb") local template = fp:read('*a') fp:close() local results = {} local last_endpos = 0 for outside, inside, endpos in template:gmatch(partten) do insert(results, format("echo(%q)", outside)) insert(results, inside) last_endpos = endpos end insert(results, format("echo(%q)", template:sub(last_endpos))) results = concat(results, "\n") bitcode = assert(loadstring(results)) loaded[path] = bitcode end local env = { include = include, echo = echo, ob_start = ob_start, ob_get_clean = ob_get_clean } setmetatable(env, {__index = function(tb, k) return params[k] or _G[k] end}) setfenv(bitcode, env) bitcode() end for i = 1, 100000 do ob_start() include(arg[1], { params = { a = '1234', b = '4321' } }) ob_get_clean() end |
master.html
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
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> < html lang = 'zh-CN' xml:lang = 'zh-CN' xmlns = 'http://www.w3.org/1999/xhtml' > < head > < meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" /> < meta http-equiv = "Content-Language" content = "zh-CN" /> < meta name = "robots" content = "index, follow" /> < link rel = "shortcut icon" type = "image/x-icon" href = "/img/favicon.ico" /> < title > child's personal page - 开源中国社区</ title > < link rel = "stylesheet/less" href = "http://my.oschina.net/lostchild/styles.less?ver=20131219&date=20131110185237" type = "text/css" media = "screen" /> < link rel = "stylesheet" href = "/js/2012/poshytip/tip-yellowsimple/tip-yellowsimple.css" type = "text/css" /> < link rel = "stylesheet" type = "text/css" href = "/js/2011/fancybox/jquery.fancybox-1.3.4.css" media = "screen" /> < script type = "text/javascript" src = "/js/2012/jquery-1.7.1.min.js" ></ script > < script type = "text/javascript" src = "/js/2012/jquery.form.js" ></ script > < script type = "text/javascript" src = "/js/2011/fancybox/jquery.fancybox-1.3.4.pack.js" ></ script > < script type = "text/javascript" src = "/js/2012/poshytip/jquery.poshytip.min.js" ></ script > < script type = "text/javascript" src = "/js/2011/oschina.js?ver=20121007" ></ script > < script type = "text/javascript" src = "/js/2012/less-1.3.0.min.js" ></ script > < script type = "text/javascript" src = "/js/scrolltopcontrol.js" ></ script > < script type = 'text/javascript' src = '/js/jquery/jquery.atwho.js?ver=2013112501' ></ script > < link rel = "stylesheet" type = "text/css" href = "/js/jquery/jquery.atwho.css" /> < link rel = "alternate" type = "application/rss+xml" title = "lostchild最新博客" href = "http://my.oschina.net/lostchild/rss" /> < link rel = "EditURI" type = "application/rsd+xml" title = "RSD" href = "http://my.oschina.net/action/xmlrpc/rsd?space=1397642" /> < link rel = "wlwmanifest" type = "application/wlwmanifest+xml" href = "http://my.oschina.net/action/xmlrpc/wlwmanifest?space=1397642" /> {# echo(header) #} </ head > < body > {# echo(content) #} < body > </ html > |
temp.html,继承master.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
{# ob_start() #} < script > alert("hello World") </ script > {# local header = ob_get_clean() #} {# ob_start() #} < table > {# for k, v in pairs(params) do #} < tr > < td >{# echo(k) #}</ td > < td >{# echo(v) #}</ td > </ tr > {# end #} </ table > {# local content = ob_get_clean() #} {# include('master.html', {header = header, content = content}) #} |
循环十万次测试渲染速度(阿里云最便宜一款vps)
1
|
[root@AY130801221248587d02Z ~] # time lua ltemplate.lua temp.htmlreal 0m1.867s |
1
2
|
user 0m1.862s sys 0m0.004s |
总结
由此可见渲染的速度还是非常快的,可以将此原型用于嵌入式设备中的页面上(用大量js实现的嵌入式设备页面兼容性不好)。而且嵌入式设备的界面需要简单明确,所以也不用太丰富的模版功能。
原理很简单:
1.用lua版的正则把模版内{#与#}之间的内容挖出来,原样输出成lua代码,其它部分则生成使用echo打印到某个缓冲区的lua代码。
2.将这个生成出来的代码使用loadstring编译。
3.通过setfenv实现loadstring后的模拟环境配置(用以提供模版内使用的echo,ob_start等函数,以及传入的参数)
4.执行这个编译后的函数即可。