Nodejs入门实践第一讲Nodejs基础
Nodejs是javascript的运行程序,使用Nodejs最大的优点是可以让javascript运行在服务器端,NodeJS是基于chrome的v8架构的,它主要的的特点是基于异步的I/O处理,所有的事件都会被事件循环器处理,当事件完成通过回调函数来传递结果,这和典型的Ajax请求一样。这样直接导致Node的程序都是单线程的,单线程的优点是程序设计简单,不用考虑复杂的线程通信,这样也就没有所谓的死锁问题,虽然Node是单线程,但由于其异步执行的优势,使得Node也可以轻松的实现并发。
NodeJS的安装
直接通过 https://nodejs.org/en/ 网站即可下载Nodejs,当前的最新版本9.3.0,建议使用8.9.3稳定版,下载NodeJS的时候依然建议下载非安装版,选择other download。
下载完成之后,解压,把Nodejs的安装目录添加到环境变量的path中,安装就完成了(注意Nodejs中没有bin路径)。
NPM简介
要很好的使用npm,在目前的NodeJS中,npm是自动安装的,大家可以发现NodeJS目录中有npm.cmd程序,这是一个可执行文件,它用来运行npm,npm是一个模块管理工具,有点类似于maven,开发人员可以将模块下载到项目中或者一个全局的位置,全局的位置默认会在NodeJS安装目录的node_modules 文件夹中。这里仅仅只介绍几个简单的命令,如果希望详细研究NPM,可以查询npm的官方文档。
- 通过命令npm -v 可以查询npm的版本
使用npm install可以安装模块,有一个非常好用的前台模块管理工具bower,我们安装一下bower,通过如下命令可以安装 - npm install bower -g
加上-g表示全局安装,安装完成之后会存储到nodejs目录的node_modules文件夹中。如果不使用全局安装会自动安装在本地目录中。另外可以通过@来指定安装的版本号 - npm install jquery@latest -g
已上安装了jquery的最新版。另外通过remove可以移除module - npm remove bower -g
nodejs起步
nodejs是一个javascript的运行环境,要运行第一个helloworld的程序,首先建立一个js的文件,我建立了begin.js在该文件中写了一行代码
- console.log(“hello world!”);
- node begin.js
require介绍
在Nodejs中提供了require函数来加载另外一个模块,这个模块可以是通过npm下载的也可以是自定义模块,首先我们自己定义一个函数模块,创建method.js文件
exports.M = {
begin: function() {
console.log("begin js");
},
end: function () {
console.log("end js");
}
}
已上代码通过exports生成了一个M模块,里面有begin和end两个方法。下面在一个module1.js文件中引入该模块
var m = require("./methods")
console.log(m);
m.M.begin();
m.M.end();
通过require引入了该模块,注意要加上./ ,另外就是methods不加js,并且定义了变量m来存储该模块,此后即可通过m.M来引入模块中的方法。
创建一个nodejs的server
Nodejs由于是javascript的运行环境,所以我们可以直接将javascript运行在服务器端,接下来我们编写一个server.js来启动一个简单的服务。首先创建server.js文件,完成如下几个步骤
- 引入http模块
var http = require(“http”) - 创建server
http.createServer(serverOk).listen(8088);
已上代码创建了一个server,当server创建完成之后会执行回调函数serverOk,该回调函数中有两个参数一个是request,另外一个是response。该server启动在8088端口中。 - 编写回调函数
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
resp.write("hello nodejs!");
resp.end();
};
回调函数有两个参数,req等于request对象,resp等于response对象,首先使用resp.writeHead()编写简单的输出信息,状态为200,类型是原始类型,并且输出了hello nodejs,最后通过resp.end()结束输出。
基于模块来修改上一个程序
我们可以将创建服务器的这段代码编写到一个模块中,首先创建server_module.js
var http = require("http");
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
resp.write("hello node module!");
resp.end();
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
这里变换了一种写法,首先在exports前增加了module,个人感觉这样说明要清晰一些,当然module是可以省略的,另外就是该module并没有编写具体的导出的名称,此时可以直接调用,该module中有两个方法,startServer表示启动服务,此时回调serverOk写在了模块的外面,这表示serverOk是私有的,不会被导出(就当前例子中,该方法也没有导出的意义)。调用代码也比较简单,创建文件test.js
var Server = require("./server_model");
console.log(Server);//输出确定仅仅导出startServer
Server.startServer(8099);
渲染html文件
渲染html是比较重要的一个步骤,Nodejs通过文件的读写来完成该操作,首先需要引入fs这个模块
接着通过fs.ReadFile可以读取文件
var fs = require("fs");
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
}
resp.writeHead(200,{"Content-type":"text/html"});
resp.write(data);
resp.end();
});
第一个参数表示file的路径,第二个参数用来存储传入的数据,第三个参数就是回调,回调中有两个参数,第一个表示error,如果发现错误就会为第一个参数赋值,第二个参数表示如果成功返回的内容。代码中首先判断了是否有error,如果没有error就直接输出data,data就是读取到的html的文件内容,注意content-type的类型必须修改为text/html。如果发现错误直接显示404.
完整代码如下所示
var http = require("http");
var fs = require("fs");
function renderHTML(path,resp) {
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
} else {
resp.write(data);
}
resp.end();
});
}
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/plain"});
//渲染hello.html
renderHTML("./hello.html",resp);
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
调用代码和上一节类似,然后看一下hello.html文件并且完成服务器的启动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello html</h1>
</body>
</html>
路由
这一小节将要实现不同的请求访问不同的页面,操作原理非常简单,通过request的url可以获取访问路径,通过url模块中的parse方法可以将url转换为json对象,其中pathname可以获取访问的路径变量。将server_module.js的代码稍作调整即可
var http = require("http");
var fs = require("fs");
var url = require("url")
function renderHTML(path,resp) {
//路径判断
if(path=="/"||path=="") {
path = "./index.html";
} else {
path = "./"+path+".html";
}
//console.log(path);
fs.readFile(path,null,function (error,data) {
if(error) {
resp.writeHead(404);
resp.write("find file error!");
} else {
resp.write(data);
}
resp.end();
});
}
function serverOk(req,resp) {
resp.writeHead(200,{"Content-type":"text/html"});
//获得访问的路径,如果输入localhost:8089/abc/bbd会得到/abc/bbd
var pathname = url.parse(req.url).pathname;
renderHTML(pathname,resp);
}
module.exports = {
startServer: function(port) {
http.createServer(serverOk).listen(port);
}
};
这里简单实现了Nodejs的基本流程,但在实际开发中一般都不会使用原生的方法来处理,Nodejs中有大量的模块可以帮助开发人员来完成这些操作.
demo 请求参数获取
- router.js
function route(pathname) {
pathname = pathname.substring(1, pathname.length);
console.log("About to route a request for " + pathname);
//var strs = pathname.split('&');
//for (var i = 0; i < strs.length; i++) {
// console.log(strs[i]);
//}
if (pathname == 'testFun') {
console.log('filename: ' + __filename);
console.log('dirname: '+__dirname);
testFun();
}
}
function testFun() {
//for (var i = 0; i < 100000; i++) {
// console.log("testFun "+i);
//}
// 输出当前目录
console.log('当前目录: ' + process.cwd());
// 输出当前版本
console.log('当前版本: ' + process.version);
// 输出内存使用情况
console.log(process.memoryUsage());
}
exports.route = route;
- server1.js
var http = require("http");
var url = require("url");
function start(route) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log('--->'+pathname);
if (pathname != '/favicon.ico') {
console.log("Request for " + pathname + " received.");
route(pathname);
}
response.writeHead(200, { "Content-Type": "text/plain" });
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
- index.js
var server = require("./server1");
var router = require("./router");
console.log(router.route);
server.start(router.route);//启动service,传入router处理函数
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
function printHello() {
console.warn("nodejs服务正常运行中! " + new Date().Format("yyyy-MM-dd hh:mm:ss"));
}
printHello();
// 两秒后执行以上函数
setInterval(printHello, 10000);