Nodejs初识

1,428 阅读8分钟

what it is?

  • Node.js的本质是一个Javascript的解析器
  • Node.js是Javascript 的运行环境
  • Node.js是一个服务器程序
  • Node.js本身使用的是V8引擎
  • Node不是web服务器

Why use it?

  • 为了提供高性能的web服务
  • IO性能强大
  • 事件处理机制完善
  • 天然能够处理DOM
  • 社区非常活跃,生态圈日趋完善

The advantage

  • 处理大流量数据
  • 适合实时交互的应用
  • 完美支持对象数据库
  • 异步处理大量并发链接

官网地址

中文网地址

安装cnpm

  • npm install cnpm 安装cnpm

第一个node程序

  • 创建 hello.js 并编辑 console.log("helloworld")
  • node hello.js //运行

#node最简单的web服务

  • 创建 server.js

  • 引入 原生 api

var http = require('htttp');
  • 创建一个服务
http.createServer(function (request,response) {
    //定义HTTP头
    response.writeHead(200, {'Content-Type':'text/plan'});
    
    //发送相应的数据
    response.end('Hello world!\n');
}).listen(8000);

//服务运行之后输出一行信息
console.log('server is running...');
  • 运行
node server.js
  • 打开浏览器 127.0.0.1:8000

Nodejs 环境及npm命令的深入

REPL

全称交互式解释器 敲 node 命令进入 可以在环境之后 直接进行代码 的编写 运算 优点类似 浏览器的 console控制台 一般来说我们可以在此环境下 进行一些 简单的 代码运算 验证

  • ctrl + c -退出当前终端
  • ctrl + c -按下两次 退出 Node REPL
  • ctrl + d -退出Node REPL (linux环境下)
  • 向上/向下 键 -查看输入的历史命令
  • tab键 -列出当前命令
  • .help -列出使用命令
  • .break -退出多行表达式
  • .clear -退出多行表达式
  • .save filename -保存当前的Node REPL 会话到指定文件
  • .load filename -载入当前 Node REPL 会话的文件内容。

npm包管理器

  • npm install npm -g //升级npm
  • npm install express -g//安装包express
  • npm uninstall packagename // 卸载包
  • npm search packagename // 查找包
  • npm help
  • npm help install // 具体查看 某个命令
  • cnpm 与 npm 的使用方法本质是相同的 只是服务器不同 一个国内 一个国外

什么是回调

  • 函数调用方式分为三类 :同步调用、回调和异步调用。
  • 回调时一种双向调用模式
  • 可以通过回调函数来实现回调

阻塞与非阻塞

  • 阻塞和非阻塞关注的是程序在等待调用的结果(消息,返回值)时的状态。
  • 阻塞就是做不完不准回来
  • 非阻塞就是你先做,我现在看看有其他事没有,做完了告诉我一声
//阻塞时代码

var fs = require('fs');  

var data = fs.readFileSync('data.txt');   //  阻塞时用 同步读取 readFileSync  非阻塞时用  readFile

console,log(data.toString());
//非阻塞代码

var fs = require('fs');

fs.readFile('filename.txt',function(err,data){
    // todo something
    if(err){
        return console.error(err)
    }
    console.log(data.toString());
})
cosnole.log("程序执行完毕")

Node.js事件驱动机制

事件驱动模型

事件与事件绑定

  • nodejs 是一个单进程 单线程的程序,它并不能同时并发完成更多的事情,只能通过事件或者回调来实现并发效果
  • nodejs 的 api 全都是异步执行的,而且都是作为独立的线程处理的
  • nodejs 中的 几乎所有的事件 都是依据观察者模式 来实现的 观察者模式 是设计模式中的一种
  • EventEmitters 对象 产生 Events 实例

事件处理代码

//1. 引入 events对象,创建 eventEmitter对象
var events = require('events');
var eventEmitter = new events.EventEmmitter();

//2. 绑定事件处理程序
var connctHandler = function  connected(){
    console.log('connected被调用了');
};
eventEmitter.on('connection', connctHandler()); //完成事件绑定
//3.触发事件
eventEmitter.emit('connection');

console.log("程序执行完毕");

Nodejs 模块化

模块化的概念和意义

  • 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统
  • 模块是Node.js应用程序的基本组成部分
  • 文件和模块是一一对应的。一个Node.js文件就是一个模块
  • 这个文件可能是Javascript代码、JSON或者编译过的C/C++扩展
  • Node.js中存在4类模块(原生模块和3种文件模块)

Node.js中的模块

Node.js的模块加载流程

模块加载流程

文件的缓存区 有文件模块缓存区 和 原生模块缓存区

  • require 方法接受一下几种参数的传递: 1 http、fs、path等,原生模块 2 ./mod或../mod,相对路径的文件模块 3 /pathtomodule/mo,绝对路径的文件模块
  • mod,非原生模块的文件模块

模块化代码案例

//main.js  主要调用模块的文件
var Hello = require('./hello');

hello = new Hello();
hello.setName('Richard');
hello.sayHello();
//hello.js  模块文件
function Hello(){
    var name ;
    this.setName = function(argName){
        name = argName
    }
    this.sayHello = function(){
        console.log('hellko' +  name);
    }
}

module.exports = Hello;

函数

  • 在javascript 中,一个函数可以作为另一个函数的参数。
  • 我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。
  • Nodejs 中的函数使用与Javascript 类似

代码示例:

function say(word){
    console.log(word);
}
function execute(someFunction,value){
    someFunction(value);
}
execute(say,'hello')

匿名函数

function execute(someFunction,value){
    someFunction(value)
}
execute(function(word){
    console.log(word)
},'hello');

示例Ⅱ 同样的功能,不同的实现方式

//匿名函数
var http = require('http');
http.createServer(function(request,response){
    response.writeHead(200,{"Content-Type":'text/plain'});
    response.write("Hello world");
    response.end();
}).listen(8000)


//先定义后传递

var http = require("http");
function onResquest(request,reponse){
    response.writeHead(200,{"Content-Type":'text/plain'});
    response.write("Hello World");
    response.end();
}
http.createServer(onResquest).listen(8888);

路由

我们所需要的所有数据都会包含在request对象中,该对象作为onRequest()回调函数的第一个参数传递。但是为了解析这些数据,我们需要额外的Node.JS模块,他们分别是urlquerystring模块

例如我们 访问 http://localhost:8888/start?foo=bar&hello=world

                url.parse(string).query
                                    |
url.parse(string).pathname          |
                        |           |
                        |           |
                     ------ -------------------
http://localhost:8888/start?foo=bar&hello=world
                            ---       -----
                            |           |
                            |           |
querystring.parse(queryString)["foo"]   |
                                        |
                    querystring.parse(queryString)["hello"]

//server.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("Request for " + pathname + " received.");
    route(pathname,response);
   
  }
 
  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}
exports.start = start;

//router.js
function route(pathname,response) {
  if(pathname == '/'){
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }else if(pathname == "/index/home"){
    response.end('index');
  }else{
    response.end('index');
  }
}
exports.route = route;

//app.js
var server = require("./server");
var router = require("./router");
 
server.start(router.route);

获取GET请求内容

var http = require('http');
var url = require('url');
var util = require('util');  //帮助类
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);

获取POST请求内容

var http = require('http');
var querystring = require('querystring');
var util = require('util');
 
http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
 
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);

全局对象与全局变量

global 就是nodejs的全局对象 类比javascript的window

  • __filename __filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。

  • __dirname __dirname 表示当前执行脚本所在的目录。

  • setTimeout(cb, ms) setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。返回一个代表定时器的句柄值。

  • clearTimeout(t) clearTimeout( t ) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。

  • setInterval(cb, ms) setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。

  • process process 是一个全局变量,即 global 对象的属性。它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。下面将会介绍 process 对象的一些最常用的成员方法。

工具util

underscore.js

文件系统

读取文件

var fs = require("fs");

// 异步读取
fs.readFile('input.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }
   console.log("异步读取: " + data.toString());
});
// 同步读取
var data = fs.readFileSync('input.txt');
console.log("同步读取: " + data.toString());

console.log("程序执行完毕。");



打开文件

fs.open(path, flags[, mode], callback) 参数说明:

  • path - 文件的路径。
  • flags - 文件打开的行为。
  • mode - 设置文件模式(权限),文件创建默认权限为 0666(可读,可写)。
  • callback - 回调函数,带有两个参数如:callback(err, fd)。

获取文件信息

fs.stat(path, callback) 参数说明

  • path - 文件路径。
  • callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。

写入文件

fs.writeFile(file, data[, options], callback)

  • file - 文件名或文件描述符。
  • data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(缓冲) 对象。
  • options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 , flag 为 'w'
  • callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
var fs = require("fs");

console.log("准备写入文件");
fs.writeFile('input.txt', '我是通 过fs.writeFile 写入文件的内容',  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("数据写入成功!");
   console.log("--------我是分割线-------------")
   console.log("读取写入的数据!");
   fs.readFile('input.txt', function (err, data) {
      if (err) {
         return console.error(err);
      }
      console.log("异步读取文件数据: " + data.toString());
   });
});

等等 方法 参考 菜鸟教程