thinkjs使用小结

这是俺这几天使用thinkjs的一些心得,由于没接触过nodejs和异步编程,代码很ZHA,如果有误人子弟请说明。。。谢谢

首先你要对她(thinkjs)有部分的了解,什么?不太熟?请移步: http://www.thinkjs.org/doc/

俺对MVC的定义

  • M层要直接接触"库"类,所有的查询要在这里进行,当然要对外暴露好点的API让C层调用更方便。遵循一个表一个M层的规则
  • V是视图,我喜欢在视图里直接循环/输出,不在做一些数据纠正等问题了,该做的都要在C里做好
  • C是控制层,一些逻辑代码将在这里写,比如:分页,判断,条件的筛选,修正一些值,输出模板,报错。经过这一层的处理,参数应该都是自己理想的,要考虑到数据空,错,非法等问题

定义module

数据库已知表 前缀_list, 在 Module 目录里新建文件 ListModule.js, 代码如下:

/**
 * 学习吧列表表模块
 * @author xieliang
 */
module.exports = Model(function() {
 'use strict';
 return {
 /**
 * 获取列表数据
 * @param {object} options 配置参数
 * @return {Promise}
 *
 * @description
 * 1, 成功的回调参数为数组 [{},{}]
 * 错误的回调参数为空数组 []
 * 2, one 成功的回调参数为对象 {a:1,b:2}
 * one 错误的回调参数为空对象 {}
 */
 get_list_data: function(options) {
 var self = this,
 sql;
 //合并参数
 options = extend(false, {
 page: 1, //分页
 limit: 'all', //偏移,如果为all则为全部
 order: 'id DESC', //排序
 cache: false, //是否加cache
 field: 'id, title, url, description, keywords', //要查的字段
 where: null, //条件
 one: false //是否只查一个
 }, options || {});
 // 查字段
 sql = self.field(options.field);
 //如果不是一个才查排序
 if (!options.one) {
 if (options.limit !== 'all') {
 sql.page(options.page, options.limit);
 }
 sql.order(options.order);
 }
 //如果有附加条件
 if (options.where) {
 sql.where(options.where);
 }
 //是否开启缓存
 if (options.cache) {
 sql.cache(true);
 }
 //如果是一个则用find查单个,否则查数组
 return options.one ? sql.find() : sql.select();
 },
 /**
 * 获取单条数据
 * @param {object} options 配置
 * @return {Promise}
 */
 get_item_data: function(options) {
 options = options || {};
 options.one = 1;
 return this.get_list_data(options);
 }
 }
});

以上两个方法为获取数据,一个是获取多条支持分页,一个是获取单条,来看代码如何获取吧:(代码写在控制器里)

//根据id查单个内容
testAction: function(){
 var self = this;
 return D('List').get_item_data({
 where: {
 id: 1
 }
 }).then(function(data){
 //data = {}
 if(isEmpty(data)){
 console.log('空数据');
 } else {
 console.log('有数据');
 }
 console.log(data);
 });
},

是不是觉得很单调? 好吧, 来个参数多的:

//like查, 并分页
test1Action: function(){
 var self = this;
 return D('List').get_item_data({
 isPage: 1,
 page: page变量,
 where: {
 class_id: 123,
 title: ['like', '%'+ key +'%']
 },
 order: 'id DESC',
 limit: 20
 }).then(function(data){
 //这里的data为数组,如果为空则是空数组
 });
},

你会不会想说这只是单个查,有时候在列表里是需要查别的表数据的,比如循环列表的每行里都有作者信息,分类信息等, 那么来看下C层吧。。。

Controller的定义

首先我强制让自己遵循一个小约定:

  • 在C层里始终把最后的代码 return 出去
  • 把最后渲染数据放在最后的一个 then 里,即使多套一个 then 也要这样做,如:
testAction: function(){
 var self = this;
 return D('List').get_list_data().then(function(data){
 // data = []
 //这里是逻辑层1,要处理得到的列表循环数组
 // data.forEach()....
 return data;
 }).then(function(data){
 //data = 列表循环数组
 //这里是逻辑层2, 要处理每行的分类+用户信息
 //var arr = [];
 //data.forEach(function(val){
 // arr.push()....
 //});
 //return Promise.all(arr)
 //
 //if(data为空则) return []
 return data;
 }).then(function(data){
 //data = 列表循环数组, 且已经处理过分类+用户信息了
 //这里是逻辑层3, 要处理一些判断,或者渲染的东东
 return data;
 }).then(function(data){
 //data = 列表循环数组, 且已经处理过分类+用户信息了, 且处理过渲染
 //这里是逻辑4,渲染模板
 self.assign("list", data....)
 self.assign....
 return self.display();//把这个return 出去 ,以便捕获异常
 });
 //在除了逻辑4以为的then,如果数据为空则直接return []交给逻辑4渲染模板为空, 如果数据错误则直接return 404的一个fn
}

我应该怎么在循环里查表呢?

/**
 * 内部调用列表
 * @description 处理分类名, 作者, 发表时间等内容
 * @param {object} options 配置
 * @return {Promise}
 */
_get_list: function(options) {
 var self = this;
 options = options || {};
 return D('Content').get_list_data(options).then(function(data) { //查分类名 + 修改url + 发布时间 + 内容
 var arr = [];
 var List = D("List");
 //如果为空则返回空数组
 if(isEmpty(data)){
 return arr;
 }
 data.forEach(function(val) {
 //查分类名
 arr.push(List.get_item_data({
 where: {
 id: val.class_id
 }
 }));
 //修正链接
 val.uri = Url.get_detail(val.id, val.url);
 //发布时间
 val.add_time = Date.elapsedDate(val.add_time * 1000, 'yyyy-M-d');
 //去html+截取
 val.article = quickHtml(val.article);
 });
 //数组异步处理
 return Promise.all(arr).then(function(list_data) {
 data.forEach(function(val, index) { //把分类的数据叠加到主数据上
 if (list_data[index]) {
 val.list_name = list_data[index].title;
 }
 });
 return data;
 });
 }).then(function(data) {
 //查作者信息 
 var arr = [];
 var User = D("User");
 //如果为空
 if(isEmpty(data)){
 return arr;
 }
 data.forEach(function(val) {
 arr.push(User.get_item_data({
 where: {
 id: val.add_uid
 }
 }));
 });
 //数组异步处理
 return Promise.all(arr).then(function(list_data) {
 data.forEach(function(val, index) {
 if (list_data[index]) {
 val.user_name = list_data[index].user_name;
 }
 });
 return data;
 });
 }).then(function(data){
 //这里是渲染模板, 如果要写成公用方法这里则删除,写在你调用之后,如:
 // 公用方法名().then(function(data){});
 self.assign('list', data);
 return self.display();
 });
},

这里循环查只是利用了数组异步处理+回调,上次听 @welefen 这种形式有个很高端的方法解决,目前俺也不会,只能这样先处理了,我相信不久将来 thinkjs 官网会出相应demo的。。。啦啦啦

此外 thinkjs 还支持base控制器,可以把一些常用的方法定义到里面,比如错误的,私有内部查询等。。。

V层就不说了,多看看模板引擎就啥也有了。。。

使用nginx做代理映射

大家都知道一般是通过域名访问web的,但nodejs好像只能绑定端口(俺才书学浅),那么我们就需要一个http server了,俺选的是nginx。。。

首先安装nginx, 然后修改nginx配置文件:

server {
 listen 80;//http端口
 server_name new.xuexb.com;//host name
 root /ssd/wwwroot/www.xuexb.com;//目录
 index index.js index.html;//默认主页
 if ( -f $request_filename/index.html ){//如果请求的路径下有index.html,则重写到这个文件
 rewrite (.*) 1ドル/index.html break;
 }
 if ( !-f $request_filename ){//如果请求的文件真实路径不存在则重写到thinkjs上
 rewrite (.*) /index.js;
 }
 location = /index.js {//配置thinkjs
 proxy_set_header Connection "";
 proxy_set_header Host $http_host;
 proxy_set_header X-NginX-Proxy true;
 proxy_pass http://127.0.0.1:81$request_uri;//这里配置thinkjs的监听端口
 proxy_redirect off;
 }
}

然后把thinkjs的端口改为已知的,比如81,然后使用提供的 sh 命令来进行后台运行服务(linux系统下),然后不出意外的话访问就会成功,这个配置感谢 @welefen,这个优势在于如果是真实路径则不启用thinkjs作服务,更快速,也可以扩展自己的 真静态 文件了,对,思路我已经想好了,只待写了。。。_

最后感谢 thinkjs,让前端也可以写后端(虽说写的很烂)。。。

w3ctech微信

扫码关注w3ctech微信公众号

共收到9条回复

  • 赞,欢迎多发thinkjs相关的文章

    回复此楼
  • 亮神好屌,哪都能见到你。。。

    回复此楼
  • 我是跟着你过来的。。。

    回复此楼
  • <h1>不错</h1><p>真好</p>

    回复此楼
  • 亮神带我飞

    回复此楼
  • 亮了

    回复此楼
  • 要求不复杂的话,nodejs 本身就能当WEB服务器,thinkjs里面把配置项port: 8360,改成port: 80,就行了,访问的时候用个http://localhost/index/index 是OK的

    回复此楼
  • @老六 uncaughtexception 有什么好的处理方法?

    回复此楼
  • @Doerme 用domain模块。 如果用thinkjs,框架已经帮你做了,应用里不用处理了。

    回复此楼

AltStyle によって変換されたページ (->オリジナル) /