1 Star 0 Fork 0

郭剑翔/test-demo

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
index.html 4.74 KB
一键复制 编辑 原始数据 按行查看 历史
郭剑翔 提交于 2024-01-07 20:35 +08:00 . art-template源码浅析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>art-template为什么快</title>
<script src="./template-web.js"></script>
</head>
<body>
<div id="wrap"></div>
<script type="text/html" id="tpl">
{{if user}}
<div>{{ user.name }}</div>
{{/if}}
</script>
<button id="redo">rerender</button>
<script>
const user = {
name: '你的名字'
}
const str = template('tpl', {user})
document.querySelector('#wrap').innerHTML = str
/*
1. 模板引擎内部维护了一个缓存,cache了对应模板的rende函数,如果发现已经缓存过,则直接使用缓存
2. 恰如二次调用就能用缓存
分析生成过程:
1. document.getElementById读取模板字符串(很可能多个换行),可以看到script:type=text/html是为了浏览器更好隐藏且不执行(nodejs中为读取文件内容:fs.readFileSync)
2. html-minifier 出名的压缩
3. Compiler重头戏:
3.1 /{{([@#]?)[ \t]*(\/?)([\w\W]*?)[ \t]*}}/ vs {{([\w\W]*?)}} 没看出有什么不同?:想匹配出来组
{{if user}} 拿表达式出来: if user
3.1.1 词法分析为[if, ' ', user]
3.1.1.1 [{type: 'name', value: 'if'}, {t:'string'|'whitespace'?}, {t: 'name'}] => [{t: 命中关键字,变keyword},..,..]
if命中了, 抽出后者所有,包装成code:`if (user) {`
{{user.name}} 拿表达式出来: user.name
3.1.2 词法分析为[user, ., name]
3.1.2.1 [{type: 'name', value: 'user'}, {t:"punctuator"}, {t: 'name'}]
啥也不是,包装成code:`user.name`
3.1.3 词法分析为[/if] 是结束的意思
3.1.2.1 [{type: 'keyword', value: 'if'}]
是结束意思,包装成code:`}`
3.1.4 tokens组合成code
3.2 目前只有三个有code,其余都是string,接下来是解析如字符串:
3.2.1 直接输出code: $$out+=' \n'
3.2.2
3.2.2.1 把【code:`if (user) {`】解析为[{"type":"keyword","value":"if"},{"type":"punctuator","value":"("},{"type":"name","value":"user"},{"type":"punctuator","value":")"},{"type":"punctuator","value":"{"}]
3.2.2.2 获取变量列表: 即便有user.name也取user(遇到.停止fitler)
3.2.2.2 注入上下文:contextMap[user] = "$data.user"
3.2.3 检测有output,是escape: 输出code: "$$out+=$escape(user.name)"
3.2.3.1 把【code: "$$out+=$escape(user.name)"】解析为
'[{"type":"name","value":"$$out"},{"type":"punctuator","value":"+="},{"type":"name","value":"$escape"},{"type":"punctuator","value":"("},{"type":"name","value":"user"},{"type":"punctuator","value":"."},{"type":"name","value":"name"},{"type":"punctuator","value":")"}]'
3.2.3.2 获取变量列表:`[{"name":"$$out","value":"''"},{"name":"user","value":"$data.user"},{"name":"$escape","value":"$imports.$escape"}]`
3.2.2.2 注入上下文:$$out 和$escape(user前面注入过了 可以不注入)
3.2.4 tokens组合成script
3.3 script生成render
3.3.1 stacks.push('function(' + DATA + '){'); 首行注入数据(模拟填充)
上下文变更:name=$data.name,遇到compileDebug则最外层包一层trycatch
$out是输出用的,其余都是变量,最后加上一行: return $out
最后用\n拼起来 fn=new Function
3.3.2 用render闭包保住fn,用caches.set('tpl', render)
4. render执行,输出$out
3. 重复1
*/
document.querySelector('#redo').addEventListener('click', ()=>{
user.name = '我的名字'
const str = template('tpl', {user})
document.querySelector('#wrap').innerHTML = str
})
</script>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wxwxnzm/test-demo.git
git@gitee.com:wxwxnzm/test-demo.git
wxwxnzm
test-demo
test-demo
master

搜索帮助