Node模版实现原理
发布于 12 年前 作者 zhuwenlong 6137 次浏览 最后一次编辑是 8 年前

看到很多人用的是express 但是我不想用第三方模版 问一下自己写的话要怎么实现

原理是node 引入 .html 然后 replace 标记的地方(如 <%%>)么,然后再send回去么?

19 回复

思路是对的。模板就是做变量替换。 好的模板支持 for in, if else。这些功能自己实现就不那么容易了。

我弄过一个 (后来半途而废了) 遇到了这些问题

  • 异步读模板文件还是同步读?
  • 模板里面某个变量能不能是异步获取的, 还是说所有内容都要等到数据准备完毕之后填入模板? (比如, 模板里一个分支, 如果满足条件就去查数据库里面的 x, 否则去查数据库里面的 y, 如果预先把 x 跟 y 都准备好就有点浪费了, 不过这个问题可能纯粹是我吃饱了撑的, 应该在 handler 里面解决?)

倒不是说这些解决不了, 只是解决方案很恶心, 回调套回调什么的… 所以最近在考虑弄个编译器先把回调给扭过来 (参考赵老师的 wind.js)

我也想知道, 那种挖空格一样的模板引擎是怎么写出来的?

高性能的模板是有“预编译”的,最终会创建一个函数,输入值,输出结果。 例如value is {value}可能会“编译”成 function(value) { return “value is”+value; }

这样的话第一次读取模板肯定是同步读取的, 而且如果运行时模板文件发生了变化, 页面不会立即更改, 必须重启服务器.

用fs 打开html文件 替换变量 然后再输出? 总觉得绕来绕去的,会不会效率上会有影响呢? 难道php 等也是这个原理么?

文件操作是慢一些。好的模板引擎会cache模板文件内容和对模板文件内容进行预处理。

我会选异步处理。小文件用同步还说得过去,文件多了就可能把主程序堵上了。

@neuront 不觉得需要重启服务器,重新“编译”生成就ok了。 既然是模板,就意味着用得多,变得不多,性能方面必然需要考虑。 另外,读取模板同步异步什么的,这个不属于模板的事情吧?nodejs的优势就是异步开发,天生的,你觉得回调写起来很麻烦是因为没有找到合适的异步开发模式,可以看看express的处理流程,每一步都可以是异步的。

@cyrilluce 要判断是不是需要重新编译, ok, 查看文件最后修改时间对吧, fs.stat 这是个异步调用. 所以肯定不是阁下所说的那样 function(value) { return xxx } 而是

function(path, value, callback) {
   fs.stat(path, function(err, stat) {
       // if (err) ???
       if (lastCompileTime < stat.mtime) {
           // recompile
       }
       callback(xxx);
   });
}

这样就恶心了. 愚见.

@neuront 只是你还没适应一切都异步的编码,或者说现在还没有一个很方便开发异步逻辑的框架或模式。直接写匿名函数当作回调来实现异步是最原始直观的一种方式,但当一个流程中异步操作多了嵌套起来就要人命了。现在我们讨论的已经不是模板的问题,而是编码方式的问题。

其实nodejs开发我只是业余尝试过,做了一个和express比较像的半成品(不习惯它的单流水线处理,不太灵活)。不过工作中是用ExtJs开发RIA界面,异步流程一点不少,比如:用户确认、ajax请求、等待用户输入表单等等,用回调开发起来一样要人命。前两年在网上看过一些异步开发库,但都比较死板,和express一样一条路走到死,不易于扩展实现各类功能,于是自己写了个。

现在开发时使用自己写的逻辑控制器: 每个新的流程触发时会有个【输入数据对象】(比如点击删除按钮,就会有act:delete及selected:records这些属性); 将每一步操作都抽象为【动作】,每个动作都可能是异步的,执行后有输出结果; 控制器根据【输入数据对象】与前次【动作】的属性及它的执行结果来判断下一步该执行什么动作。

以上,这样子的话开发起来就很方便了,将之前回调方式的异步编码平铺开。【动作】都是无状态的,可以复用。你这里说的模板问题就相当于这样子: [数据读取] -> [判断模板是否最新] -> [读取模板] -> [输出结果] 动作定义就像这样子: read : {success:ifTpl, failure:showerr}, ifTpl :{success:readTpl, failure:showerr}, readTpl : {success:output, failure:showerr}, output:{}, showerr:{} 控制器在接收到请求时,将数据打包传给read动作处理,根据执行结果转向不同的动作,直到流程结束。

可能表述得不太好,以上模式仅供参考。

@cyrilluce 愚现在也在折腾一个反异步代码的东西, 是个编译器, 主要是想把异步代码写得很同步, 比如 js 里的

fs.stat(path, function(err, stat) {
    if (lastCompileTime < stat.mtime) {
        fs.read(path, function(err, content) {
            compile(content);
        }
    }
});

等价地写作

fs.stat(path, %(err0, stat))
if (lastCompileTime < stat.mtime)
    fs.read(path, %(err1, content))
    compile(content)

大概是这个样子╮(╯▽╰)╭打算在春节前发布一个版本求指教求虐.

@neuront 你的这种设计已经有类似的库了(Jscex),不过个人觉得实现太暴力,容易失控。

把ejs或者jade读懂不就知道该怎么写了?直接觉得不好,可以写,但是请你先学习基本的东西再来问“XXX怎么写”?

已经有些好的放在那里了,开源的,自己看代码很难么。

每个人都有自己的学习风格好么?! 正因为是初学者才想从基础搞起,不想去用模版什么的?! 正因为是初学者开源码才觉得吃力,才要去边问边学?OK?!

@cyrilluce 现在改名叫windjs,我有在用

模板里还去查数据库。。。感觉不太好。

终于找你了,不知道你还在折腾不! 这里有个腾讯的讲了些原理 http://cdc.tencent.com/?p=5723 你可以参看下!

还在折腾 谢了~

回到顶部