Ghost blog的由来,曾经有位wordpress的兄弟,觉得wordpress越来越不简洁,一气之下跑出来自创门户,于是诞生了一个新的开源博客系统ghost,用时下非常时髦的Node.js编写,前几天刚刚发布,一时间赚足眼球。主页在这
https://ghost.org/ ,然后很奇葩的在官方论坛上发现好多中国同学发中文贴,虽然没什么不对,不过总觉得有些违和感。
闲来无事就download了源码看了下,顺便也学习下Node,一直以来看到的Node的资料都是各种入门材料,这次有大神的源码就很乐呵的读一下。
看了俩文件,比较简单,随便写一下
整个blog系统启动入口是index.js,而index.js里主要就是调用了load config相关的方法。
configLoader.loadConfig().then(function () {
// The server and its dependencies require a populated config
require('./core/server');
}).otherwise(error.logAndThrowError);
所以就进入loadConfig方法实现去看一下,是在core/目录下的config-loader.js文件,内部主要有三个方法,两个private方法writeConfigFile 和 validateConfigEnvironment, 以及一个public方法loadConfig,因此index.js调用的就是这个public方法。
先说明一下两个private方法。
function writeConfigFile() {
var written = when.defer();
/* Check for config file and copy from config.example.js
if one doesn't exist. After that, start the server. */
fs.exists('config.example.js', function checkTemplate(templateExists) {
var read,
write;
if (!templateExists) {
return errors.logError(new Error('Could not locate a configuration file.'), process.cwd(), 'Please check your deployment for config.js or config.example.js.');
}
// Copy config.example.js => config.js
read = fs.createReadStream('config.example.js');
read.on('error', function (err) {
return errors.logError(new Error('Could not open config.example.js for read.'), process.cwd(), 'Please check your deployment for config.js or config.example.js.');
});
read.on('end', written.resolve);
write = fs.createWriteStream('config.js');
write.on('error', function (err) {
return errors.logError(new Error('Could not open config.js for write.'), process.cwd(), 'Please check your deployment for config.js or config.example.js.');
});
read.pipe(write);
});
return written.promise;
}
该方法作用是将一份模板配置文件config.example.js的内容写进系统所需的config.js中,防止不存在config.js,特别是第一次启动时是不存在config.js的。另外你也可以手动创建config.js。当然如果你两个文件都没有……那也不行
具体实现,使用到了node的file system模块fs,基本的读/写流
function validateConfigEnvironment() {
var envVal = process.env.NODE_ENV || 'undefined',
hasHostAndPort,
hasSocket,
config,
parsedUrl;
try {
config = require('../config')[envVal];
} catch (ignore) {
}
// Check if we don't even have a config
if (!config) {
errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), "NODE_ENV=" + envVal, 'Ensure your config.js has a section for the current NODE_ENV value');
return when.reject();
}
// Check that our url is valid
parsedUrl = url.parse(config.url || 'invalid');
if (!parsedUrl.protocol || !parsedUrl.host) {
errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting');
return when.reject();
}
// Check that we have database values
if (!config.database) {
errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration');
return when.reject();
}
hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
hasSocket = config.server && !!config.server.socket;
// Check for valid server host and port values
if (!config.server || !(hasHostAndPort || hasSocket)) {
errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
return when.reject();
}
return when.resolve();
}
该方法用来检验配置文件的合法性,检验host&port和socket至少得有一项,以满足服务访问需求。
这两个方法本身逻辑很简单,不过其中有一个东西比较特殊,那就是when模块的使用。简单介绍一下,when模块主要用来实现更简洁的同步编程。我们都知道,在nodejs里绝大部分方法都是异步执行的,如果你需要两个方法顺序的同步执行,就必须将方法B作为参数出入方法A中,作为回掉函数。如此一来,复杂的逻辑会使得代码的嵌套极为凶残。很多人都提供了一些同步代码编写的工具,其中when就是一个。
于是我们结合第一个方法来看一下when的用法。首先需要定义一个defer变量,var written = when.defer();当read结束,即end事件触发时,会执行written.resolve(),resolve表示执行成功,暂时理解为是一个成功标志。方法的最后需要返回written.promise;。那么这个resolve有什么作用呢,请看第三个方法
exports.loadConfig = function () {
var loaded = when.defer();
/* Check for config file and copy from config.example.js
if one doesn't exist. After that, start the server. */
fs.exists('config.js', function checkConfig(configExists) {
if (configExists) {
validateConfigEnvironment().then(loaded.resolve).otherwise(loaded.reject);
} else {
writeConfigFile().then(validateConfigEnvironment).then(loaded.resolve).otherwise(loaded.reject);
}
});
return loaded.promise;
};
writeConfigFile().then(validateConfigEnvironment),也就是说,当resolve后,就会继续执行then传入的方法。代码风格上写成链式,当然要比传参更直观。那么除了执行成功,必然还有执行失败,即reject方法。参考validateConfigEnvironment方法,凡是判断配置invalid后,都会执行when.reject(),然后会怎么样呢,表面上看似乎应该进入otherwise而不是then,这样也很明了。但事实上它依然会进入then方法。这是为什么呢,因为then方法有三个参数,其中前两个就是resolve及reject后的回掉函数,哪种结果就调用哪种回掉函数。而上文中的then只提供了一个参数即第一个参数,所以可以理解为执行成功后续。同时,otherwise方法其实是then的一个变种,即不提供第一个参数的then方法,因此可以理解为执行失败后续。
when了解以后,最后来过loadConfig方法,首先判断配置文件是否存在,存在就直接判断合法性最后判断状态resolve还是reject,不存在就先拷贝再验证合法性,最后也要判断状态。这里最后达成的状态作用于index.js的调用。成功继续加载server,错误就结束系统。
加载配置的逻辑基本就是这样了
分享到:
相关推荐
《深入剖析Soffes-Ghost源码》 在IT领域,源码分析是提升技术水平、理解软件工作原理的重要途径。本篇文章将详细探讨名为“Soffes-Ghost”的开源项目,通过对源码的深入解析,揭示其设计理念和实现机制,为开发者...
2. 下载最新版本的Ghost源码,可以通过GitHub或其他镜像站点获取。 3. 解压并进入下载的目录,然后运行`npm install --production`安装所需依赖。 4. 使用`npm start`启动Ghost服务,首次启动时会引导你进行数据库...
2. 下载Ghost源码:从官方GitHub仓库获取最新版本的Ghost源代码。 3. 安装依赖:在项目目录下运行`npm install`命令,安装所需依赖。 4. 配置环境:编辑`config.example.js`文件,根据实际环境修改配置信息。 5. ...
【标题】"eiriksm-ghost" 是一个与JavaScript相关的项目,可能是一个个人或团队开发的开源软件或工具,其名称暗示了它可能与Ghost博客平台有关。Ghost是一个流行的开源博客系统,由JavaScript编写,旨在提供简洁、...
INT:中间代码,当一个源程序经过语法检查后编译产生一个可执行代码 IOF:Findit文档 IQY:Microsoft Internet查询文件 ISO:根据ISD 9660有关CD-ROM文件系统标准列出CD-ROM上的文件 ISP:X-Internet签字文件 ...