tornado模板解析过程总结
0. RequestHandler中调用loader.load函数,传入模板文件名,生成模板实例
(1). 检测模板文件名,并返回合法的文件名
(2). 根据文件名做模板的内容缓存,节省了每次解析模板内容并编译的开销
(3). 如果未找到编译好的模板,则调用Template类创建新模板
1. 将内容用_parse函数逐行解析:
(1). 对于普通的表达式直接加入到_Expression实例中
(2). 遇到end则直接返回,并继续处理下一行
(3). 如果都不是,则得到操作符,例如是if,extends等等
(4). 遇到extends, import, include, set, raw, module则将他们加入到对应的类中
并将类的实例加入到body.chunks,然后处理下一行
(5). 根据之前得到的操作符,如果是apply, block, try, if, for, while
则递归调用_parse处理剩下的内容,直到遇到下一个{%
(6). 在递归的过程中,将这些块级标记中间的内容加入到对应的类中,例如_Applyblock
例如_NamedBLock和_ControlBlock
(7). 最后返回所有处理好的语句
2. 生成临时函数,这个函数用来执行,并生成最终结果
(1). 找到当前template中所有语句,是不是有extends别的模板
(2). 如果有找到,就递归调用loader.loader处理,返回的是生成的模板
(3). 反转这个包含当前模板,和extends别的模板的列表
最后被处理的模板会放在最前面,这个模板也就是最终会输出给客户的模板
(4). 在这个列表中找到引用别的block的内容,就是扩展出来的block
(5). 以最后被处理的模板作为当前模板,生成临时函数的内容
3. 循环调用当前的模板中的标记类,分别调用它们的generate函数
(1). 如果遇到_NamedBlock,将找到的named_block中的内容(引用别的block的)
写入到最后生成的模板的内容中
(2). 如果遇到_IncludeBlock,则调用loader.loader生成include模板的内容
并递归调用find_named_blocks返回被重新定义的block的内容,类似与extends标记的处理方式
(3). 其他类似与if, while, apply则调用相应的类的generate函数,没有递归的过程
(4). 将生成的临时函数,写入到StringIO中
4. 执行临时函数,生成最终函数,执行并返回结果
(1). 将上一步生成的临时函数,编译成python虚拟机的字节码
(2). 在namedspace中执行字节码: exec self.compiled in namedspace
(3). namedspace是包含默认变量,和用户变量的字典
(4). 生成最终函数,名称为_execute
(5). 调用最终函数执行结果并返回