Nodejs nodeclub源码中EJS的疑惑

Nodejs nodeclub源码中EJS的疑惑

这个????

首先你可以先了解下这个eventproxy模块,
这里有篇文章http://cnodejs.org/topic/4f76cafe8a04d82a3d556a07
或者你直接去https://github.com/JacksonTian/eventproxy这里看,

你看明白这个之后你在看这里:proxy/topic.js文件里的代码,随便一个函数都行,比如:

/**
 * 根据主题ID获取主题
 * Callback:
 * - err, 数据库错误
 * - topic, 主题
 * - tags, 标签列表
 * - author, 作者
 * - lastReply, 最后回复
 * [@param](/user/param) {String} id 主题ID
 * [@param](/user/param) {Function} callback 回调函数
 */
exports.getTopicById = function (id, callback) {
  var proxy = new EventProxy();           ----------重点注意0:这里有使用啊
  var events = ['topic', 'tags', 'author', 'last_reply'];
  proxy.assign(events, function (topic, tags, author, last_reply) {
    return callback(null, topic, tags, author, last_reply);
  }).fail(callback);

Topic.findOne({_id: id}, proxy.done(function (topic) { if (!topic) { proxy.emit(‘topic’, null); proxy.emit(‘tags’, []); proxy.emit(‘author’, null); --------重点注意1:这里是空 proxy.emit(‘last_reply’, null); return; } proxy.emit(‘topic’, topic);

// TODO: 可以只查tag_id这个字段的吧?
TopicTag.find({topic_id: topic._id}, proxy.done(function (topic_tags) {
  var tags_id = [];
  for (var i = 0; i < topic_tags.length; i++) {
    tags_id.push(topic_tags[i].tag_id);
  }
  Tag.getTagsByIds(tags_id, proxy.done('tags'));
}));

User.getUserById(topic.author_id, proxy.done('author'));       -------重点注意这里2:这里才是最重要的,如果你看懂刚才上面我推荐的,那么这里你应该就没有难度了!    

if (topic.last_reply) {
  Reply.getReplyById(topic.last_reply, proxy.done(function (last_reply) {
    proxy.emit('last_reply', last_reply || null);
  }));
} else {
  proxy.emit('last_reply', null);
}

})); };

对了,github上面这句很重要啊,别漏掉了:

ep.done('tpl');
// 等价于
function (err, content) {
  if (err) {
    // 一旦发生异常,一律交给error事件的handler处理
    return ep.emit('error', err);
  }
  ep.emit('tpl', content);
}

你看明白了,你或许就知道为什么了!


2 回复

Nodejs nodeclub源码中EJS的疑惑

在Nodeclub源码中,EJS(Embedded JavaScript)模板引擎被广泛使用。本文将通过分析nodeclub中的一个具体函数来帮助理解EJS是如何与EventProxy模块协同工作的。

首先了解EventProxy模块

EventProxy是一个非常有用的模块,用于处理异步回调的管理。它可以帮助我们避免回调地狱(callback hell),使代码更清晰、更易于维护。你可以通过以下链接进一步了解EventProxy

示例代码解析

接下来,我们将分析nodeclub源码中的getTopicById函数,该函数用于根据主题ID获取主题信息。

/**
 * 根据主题ID获取主题
 * Callback:
 * - err, 数据库错误
 * - topic, 主题
 * - tags, 标签列表
 * - author, 作者
 * - lastReply, 最后回复
 * @param {String} id 主题ID
 * @param {Function} callback 回调函数
 */
exports.getTopicById = function (id, callback) {
  var proxy = new EventProxy();           // 创建一个新的EventProxy实例
  var events = ['topic', 'tags', 'author', 'last_reply'];
  
  proxy.assign(events, function (topic, tags, author, last_reply) {
    return callback(null, topic, tags, author, last_reply);
  }).fail(callback);

  Topic.findOne({_id: id}, proxy.done(function (topic) {
    if (!topic) {
      proxy.emit('topic', null);
      proxy.emit('tags', []);
      proxy.emit('author', null);
      proxy.emit('last_reply', null);
      return;
    }
    
    proxy.emit('topic', topic);

    // 获取标签
    TopicTag.find({topic_id: topic._id}, proxy.done(function (topic_tags) {
      var tags_id = [];
      for (var i = 0; i < topic_tags.length; i++) {
        tags_id.push(topic_tags[i].tag_id);
      }
      Tag.getTagsByIds(tags_id, proxy.done('tags'));
    }));

    // 获取作者
    User.getUserById(topic.author_id, proxy.done('author'));

    // 获取最后回复
    if (topic.last_reply) {
      Reply.getReplyById(topic.last_reply, proxy.done(function (last_reply) {
        proxy.emit('last_reply', last_reply || null);
      }));
    } else {
      proxy.emit('last_reply', null);
    }
  }));
};

关键点解析

  1. 创建EventProxy实例

    var proxy = new EventProxy();
    

    这里创建了一个新的EventProxy实例,用于管理后续的异步操作。

  2. 定义需要监听的事件

    var events = ['topic', 'tags', 'author', 'last_reply'];
    

    这里定义了我们需要监听的事件名称。

  3. 设置事件处理逻辑

    proxy.assign(events, function (topic, tags, author, last_reply) {
      return callback(null, topic, tags, author, last_reply);
    }).fail(callback);
    

    assign方法用于指定当所有指定的事件都被触发时,执行的回调函数。如果其中任何一个事件未触发,则会调用fail方法中的回调函数。

  4. 查询数据库并触发事件

    Topic.findOne({_id: id}, proxy.done(function (topic) {
      // ...
    }));
    

    使用findOne方法查询主题信息,并通过proxy.done方法将结果传递给下一个处理步骤。

  5. 异步处理其他信息

    TopicTag.find({topic_id: topic._id}, proxy.done(function (topic_tags) {
      // ...
    }));
    User.getUserById(topic.author_id, proxy.done('author'));
    

    查询标签信息和作者信息,并通过proxy.done方法将结果传递给下一个处理步骤。

通过以上代码和注释,我们可以看到EventProxy如何有效地管理异步操作,确保所有数据都准备好后再进行下一步处理。这种模式使得代码更加清晰且易于维护。


在这个问题中,讨论的是 Nodeclub 源码中的 EJS 模板引擎以及 EventProxy 的使用。为了更好地理解这个问题,我们需要先了解 EventProxy 的功能。EventProxy 是一个帮助管理异步操作的模块,可以简化多步骤异步操作的逻辑。

代码解析

getTopicById 函数中,我们看到以下几个关键点:

  1. 创建 EventProxy 实例

    var proxy = new EventProxy();
    
  2. 定义需要触发的事件

    var events = ['topic', 'tags', 'author', 'last_reply'];
    
  3. 分配事件处理程序

    proxy.assign(events, function (topic, tags, author, last_reply) {
      return callback(null, topic, tags, author, last_reply);
    }).fail(callback);
    
  4. 查询主题

    Topic.findOne({_id: id}, proxy.done(function (topic) {
      if (!topic) {
        proxy.emit('topic', null);
        proxy.emit('tags', []);
        proxy.emit('author', null);
        proxy.emit('last_reply', null);
        return;
      }
      proxy.emit('topic', topic);
    }));
    
  5. 查询标签

    TopicTag.find({topic_id: topic._id}, proxy.done(function (topic_tags) {
      var tags_id = [];
      for (var i = 0; i < topic_tags.length; i++) {
        tags_id.push(topic_tags[i].tag_id);
      }
      Tag.getTagsByIds(tags_id, proxy.done('tags'));
    }));
    
  6. 查询作者

    User.getUserById(topic.author_id, proxy.done('author'));
    
  7. 查询最后回复

    if (topic.last_reply) {
      Reply.getReplyById(topic.last_reply, proxy.done(function (last_reply) {
        proxy.emit('last_reply', last_reply || null);
      }));
    } else {
      proxy.emit('last_reply', null);
    }
    

重点理解

  • EventProxy 的核心是管理多个异步操作,并在所有操作完成后触发一个最终的回调。
  • 在上述代码中,proxy.done 方法用于指定每个异步操作完成后的回调函数。
  • proxy.assign 方法用于将多个事件绑定到一个回调函数,并在所有事件触发后执行该回调函数。
  • 如果某个操作失败,proxy.fail 会捕获并处理错误。

通过这种方式,EventProxy 可以有效地管理复杂的异步逻辑,确保所有数据准备好后再进行下一步操作。

回到顶部