Node.js
global
和 process
对象
在 Node.js 中,唯一的全局对象称为 global
,这个对象的属性和方法可以通过 console.log(console)
查看。而 process
对象则代表当前的进程:
> process === global.process;
true
> process.version;
'v5.2.0'
> process.platform;
'darwin'
> process.arch;
'x64'
> process.cwd(); //返回当前工作目录
'/Users/michael'
> process.chdir('/private/tmp'); // 切换当前工作目录
undefined
> process.cwd();
'/private/tmp'
我们可以在下一次事件响应中执行代码,通过 process.nextTick()
方法:
process.nextTick(function () {
console.log('nextTick callback!');
});
console.log('nextTick was set!');
我们也可以用 exit
事件来让程序退出时执行某个函数。
fs
同步读写文件
var fs = require('fs');
var data = fs.readFileSync('163.yaml');
fs.writeFileSync('test.yaml', data)
fs
读写流
流是有顺序的数据。在 Node.js 中,流是一个对象,我们需要响应流的事件:
'use strict';
var fs = require('fs');
// 打开一个流:
var rs = fs.createReadStream('sample.txt', 'utf-8');
rs.on('data', function (chunk) {
console.log('DATA:')
console.log(chunk);
});
rs.on('end', function () {
console.log('END');
});
rs.on('error', function (err) {
console.log('ERROR: ' + err);
});
而以流的形式写入文件需要调用 write()
方法并以 end()
结束:
'use strict';
var fs = require('fs');
var ws1 = fs.createWriteStream('output1.txt', 'utf-8');
ws1.write('使用Stream写入文本数据...\n');
ws1.write('END.');
ws1.end();
var ws2 = fs.createWriteStream('output2.txt');
ws2.write(new Buffer('使用Stream写入二进制数据...\n', 'utf-8'));
ws2.write(new Buffer('END.', 'utf-8'));
ws2.end();
pipe
对接
我们可以将可读流和可写流串起来:
'use strict';
var fs = require('fs');
var rs = fs.createReadStream('sample.txt');
var ws = fs.createWriteStream('copied.txt');
rs.pipe(ws);
这样,我们可以完成文件的复制。
http
服务器
我们可以通过 http
模块的 request
和 response
处理请求:
'use strict';
var http = require('http');
var server = http.createServer(function (request, response) {
console.log(request.method + ': ' + request.url);
response.writeHead(200, {'Content-Type': 'text/html'});
response.end('<h1>Hello world!</h1>');
});
server.listen(8080);
console.log('Server is running at http://127.0.0.1:8080/');
文件服务器
首先我们将 URL 解析,然后找到对应的路径就可以了。在返回文件的时候,我们不需要读取文件,只需要将它对接上 response
这个流即可:
var server = http.createServer(function (request, response) {
var pathname = url.parse(request.url).pathname;
var filepath = path.join(root, pathname);
fs.stat(filepath, function (err, stats) {
if (!err && stats.isFile()) {
console.log('200 ' + request.url);
response.writeHead(200);
fs.createReadStream(filepath).pipe(response);
// 因为自动关闭,所以不需要手动关闭。
} else {
console.log('404 ' + request.url);
response.writeHead(404);
response.end('404 Not Found');
}
});
});
koa
中间件
对 http
的请求由多个中间件组成的处理链组成,通过不同的中间件组合我们可以实现很多功能。每个中间件通过 await next()
调用下一个函数。
app.use(async (ctx, next) => {
console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
await next(); // 调用下一个middleware
});
app.use(async (ctx, next) => {
const start = new Date().getTime(); // 当前时间
await next(); // 调用下一个middleware
const ms = new Date().getTime() - start; // 耗费时间
console.log(`Time: ${ms}ms`); // 打印耗费时间
});
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});
用 koa-router
处理不同的 URL
除了最初的一个之外,剩下的中间件都用 router
实现:
router.get('/hello/:name', async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
});
router.get('/', async (ctx, next) => {
ctx.response.body = '<h1>Index</h1>';
});
// add router middleware:
app.use(router.routes());
Nunjucks
模板引擎
首先定义一个环境:
var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('templates'));
然后进行渲染:
env.render('home.html')
处理静态文件的中间件
let staticHandler = async (ctx, next) => {
let rpath = ctx.request.path;
if (rpath.startsWith('/static/')) {
let fp = rpath.substring(1);
if (await fs.exists(fp)) {
ctx.response.type = mime.getType(fp);
ctx.response.body = await fs.readFile(fp);
} else {
ctx.response.status = 404;
}
} else {
await next();
}
};
集成 Nunjucks 的中间件
我们利用一个中间件向 ctx
绑定渲染函数:
App.use(async (ctx, next) => {
// 给ctx绑定render函数:
ctx.render = function (view, model) {
ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {}));
ctx.response.type = 'text/html';
};
await next();
})