Node.js学习笔记(4)——除了HTTP(服务器和客户端)部分

很多node入门的书里面都会在介绍node特性的时候说:单线程,异步式I/O,事件驱动。

Node不是一门语言,它是运行在服务器端的开发平台,官方指定语言为javascript。

阻塞和线程:

线程在执行中如果遇到磁盘读写或网络通信(统称为 I/O 操作),通常要耗费较长的时间,这时操作系统会剥夺这个线程的 CPU 控制权,使其暂停执行,全力执行这个I/O操作,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。当其他完成之后,系统再恢复它对cpu的控制权,继续执行,这就是同步I/O或者阻塞式I/O。

所以这个模式之下,一个线程只能处理一个任务,要么是计算操作,要么是I/O操作等等。每当有多的请求发过来的时候,必须多加线程用来响应。

同样的,在异步式或者非阻塞式,系统对所有的I/O操作部阻塞,而是将这个耗费时间和资源的操作报告给OS,就继续执行下一条语句。当OS执行完毕这个I/O操作之后,以事件的形式通知原来请求挂载I/O操作的线程,线程会在特定的时间处理这个事情。所以,必线程必须有事件循环,不断检查有没有未处理的事件。

所以这个模式下,cpu的核心利用率永远是100%,I/O以事件形式通知。

总结:多线程同步式I/O阻塞模式通过加开线程响应更多的请求,好处是在多核cpu的情况下利用更多的核。

单线程模式异步式I/O非阻塞式一个线程永远在执行计算操作,这个线程使得cpu的核心利用率为100%。通过功能划分利用多核CPU。

这不是殊途同归吗?node采用后者的原因是什么呢?

单线程的牛逼之处在于不用创建更多的线程,也就是可以节省掉创建线程所浪费的资源。理论依据是加开一个新线程是非常耗费资源的。

关于异步式I/O(磁盘读写或网络通信)和事件驱动:

Node维护一个事件队列。

普通方式查询数据库操作:

res=db.query(‘select * from *’);

res.output();

node解决方案:

db.query(‘select * from *’, function (res){

res.output();

});

上面用到回调函数。实现非阻塞的方式请求。

弊端:一个完整的逻辑拆分为一个个事件,增加开发调试的难度;解决方案在后面提及。

两个通过node读取文件的例子fs.readFile api(异步式(回调函数来实现)和同步式):

var fs = require(‘fs‘);

fs.readFile(‘file.txt‘, ‘utf-8‘, function(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

});

console.log(‘end.‘);

var fs = require(‘fs‘);

var data = fs.readFileSync(‘file.txt‘, ‘utf-8‘);

console.log(data);

console.log(‘end.‘);

两者输出数据的顺序不同。但是功能上没有什么区别。

关于模块:

node提供了exports和require两个对象。exports是模块公开的接口,require是用于获取这个模块的接口。

实例:

创建两个文件,一个当做外面的模块进行加载module.js,另一个是程序的入口文件getmodule.js.

module.js:

var name;

exports.setname=function(name){

name=name;

};

exports.sayhello(){

console.log(‘hello’+name);

};

getmodule.js:

var test=require(‘./module.js’);

test.setname(‘zhou’);

test.sayhello();

node getmodule.js

hellozhou

这就实现了接口的封装。module.js通过exports对象吧两个函数作为间接接口,在getmodule.js中通过require加载一个模块,之后就可以直接访问module中的exports对象的成员函数。

创建包

包是模块基础上更深一步的抽象。

下面,可以将一个文件夹somepckage封装成一个模块。这个文件里里面要有一个index.js的文件,像module.js一样。然后在getmodule.js的文件里面,可以直接用var a=require(./package);

之后就可以通过a.xxxx来访问index.js里面的函数了。亲测可行。

题外话:关于全局安装依赖包和选择目录安装依赖包的优缺点。

全局的好处是可以提高程序重复利用的程度。避免同样的内容存在于多个副本。坏处是难以处理不同的版本依赖。

本地的好处是不会有不同程序依赖不同版本包的问题。同时减轻了包作者的API兼容性压力,但是缺陷是要一个个安装,非常繁琐。

node有全局和本地两种方式选择。

我们选择全局安装的理由有:本地安装不会注册path环境变量。例如在一个工程下安装的supervisor不会再另一个工程中发挥作用。

但是,使用全局安装下的包不可以通过require访问,这是一个悲伤的事。本地安装的可以通过require访问,但是不注册path环境变量;全局安装的不可以通过require访问,但是注册path环境变量。

总而言之,当我们要把某个包作为工程运行时的一部分时,通过本地模式获取,如果要

在命令行下使用,则使用全局模式安装。

还有就是怎样发布自己的npm包供全世界的人使用。

下面介绍node的核心模块。(全局变量,常用工具,事件机制,文件系统,http服务器和客户端)

全局变量

全局对象:可以在程序的任何部分访问的对象就是全局变量,类似于上面所说的全局安装。增加了path环境变量。

全局对象及其所有的属性就是全局变量,可以任意访问。

在浏览器javascript中,window就是全局变量,我们可以在任何地方使用window.open……

node中,全局对象是global。所有全局变量,都是global的属性。包括console,process等。

process:(全局变量,global的一个属性)

作用:用于描述当前node进程的对象,提供了一个与操作系统的简单接口。

process.argv:命令行参数数组,可以返回命令行的参数为一个数组,数组第一个元素为node,第二个为文件目录,以后为运行参数;

process.stdout:标准输出流,process.stdout.write()比console.log();更加接近底层;

process.stdin:标准输入流;

process.nextTick(callback):为事件循环设置一项任务,node会在下次事件循环相应的时候调用callback。比setTimeout(fn,0)更加高效。

console:用于提供控制台标准输出

console.log():

console.log (‘Hello world‘);

console.log(‘byvoid%diovyb‘);

console.log(‘byvoid%diovyb‘, 1991);

输出:

Hello world

byvoid%diovyb

byvoid1991iovyb

console.error():向标准的错误流输出

console.trace():向标准错误流输出当前的调用栈。

常用工具

var util = require(‘util‘);

util.inherits

util.inherits(constructor, superConstructor)是一个实现对象间原型继承的函数。

util.inherits(Sub, Base);

sub继承自base;

util.inspect

util.inspect(object,[showHidden],[depth],[colors])是一个将任意对象转换为字符串的方法,通常用于调试和错误输出。它至少接受一个参数 object,即要转换的对象。

depth:最大递归层数,默认两层,null不限次数直到遍历完成。

事件驱动模块events

 

events是node最重要的模块。被几乎所有的模块依赖。

事件发射器

events模块只提供了一个对象:events.EventEmitter。核心就是事件发射与事件监听器的封装。

var events = require(‘events‘);

var emitter = new events.EventEmitter();

相关API:

emitter.on(event,listener):为enent事件注册一个监听器,接受字符串event和一个回调函数listener;

emitter.emit(event,[arg1],[arg2],[arg3],[arg4])发射event事件,传递若干可选参数到事件监听器的参数表;emitter.emit(‘error‘);当 error 被发射时,EventEmitter 规定如果没有响应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。

EventEmitter.once(event, listener) 为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立刻解除该监听器。

EventEmitter.removeListener(event, listener) 移除指定事件的某个监听器,listener 必须是该事件已经注册过的监听器。

EventEmitter.removeAllListeners([event]) 移除所有事件的所有监听器,如果指定 event,则移除指定事件的所有监听器。

相当抽象,来个例子好了:

var events = require(‘events‘);

var emitter = new events.EventEmitter();

emitter.on(‘someEvent‘, function(arg1, arg2) {//为someEvent事件注册了一个监听器——一个匿名回调函数。

console.log(‘listener1‘, arg1, arg2);

});

emitter.on(‘someEvent‘, function(arg1, arg2) {/为someEvent事件又注册了一个监听器——一个匿名回调函数。

console.log(‘listener2‘, arg1, arg2);

});

emitter.emit(‘someEvent‘, ‘byvoid‘, 1991);//发射enent事件,传递两个参数到事件监听器的参数表

结果:

listener1 byvoid 1991

listener2 byvoid 1991

总结:emitter使用.on为someEvent事件注册了两个事件监听器,然后使用.enit发射事件someEvent,并传递两个参数给事件监听器。于是这两个事件监听器回调函数先后被调用。

文件操作模块(fs):

node给文件操作同时提供了异步和同步的两种方式。

异步方式:

fs.readFile(filename,[encoding],[callback(err,data)])

文件名,编码方式(缺省为二进制),回调函数。data为文件内容。

var fs = require(‘fs‘);

fs.readFile(‘content.txt‘, function(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

});

输出(假设源文件是utf-8编码):

<Buffer 54 65 78 74 20 e6 96 87 e6 9c ac e6 96 87 e4 bb b6 e7 a4 ba e4 be 8b>

指定编码方式:

var fs = require(‘fs‘);

fs.readFile(‘content.txt‘, ‘utf-8‘, function(err, data) {

if (err) {

console.error(err);//如果运行出错,err将是Error的对象。

} else {

console.log(data);

}

});

输出:
Text 文本文件示例

关于回调函数的补充:

Node.js 的异步编程接口习惯是以函数的最后一个参数为回调函数,通常一个函数只有一个回调函数。回调函数是实际参数中第一个是 err,其余的参数是其他返回的内容。如果没有发生错误,err 的值会是 null undefined。如果有错误发生,err 通常是 Error 对象的实例。

 

同步方式:

fs.readFileSync(filename,
[encoding])。

fs.open

fs.open(path,
flags, [mode], [callback(err, fd)])

路径,flag是确认文件的打开方式(读写,只读只写,创建与否),mode默认0666,回调函数传回一个文件描述符fd。

fs.read

fs.read(fd,
buffer, offset, length, position, [callback(err, bytesRead,buffer)])

比fs.readFile 提供了更底层的接口。

(文件描述符,写入buffer指向,buffer写入偏移量,读取字节数,读取起始位置,回调函数传递两个参数——字节数和缓冲区对象)

参考资料:《node.js开发指南》

(未完待续,欢迎指出错误)

时间: 2024-10-28 10:56:30

Node.js学习笔记(4)——除了HTTP(服务器和客户端)部分的相关文章

面向于初学者的Node.js学习笔记 01 搭建静态服务器

希望这篇文章能解决你这样一个问题:“我现在已经了解了一些Node.Js基本概念了,怎么搭一台静态服务器呢?” 请参考一下博主的前两篇文章: 完全面向于初学者的Node.js指南 Node.Js的Module System 以及一些常用 Module 本文实现的效果(样式就没做了,大家将就下): 列出的代码均测试可用,大家放心. What is static server? 静态服务器,有了它呢,就可以让外部访问到咱们的静态网页.在功能上:它可以给用户发送文件(如:HTML, CSS, Js等).

Node.js学习笔记【1】入门(服务器JS、函数式编程、阻塞与非阻塞、回调、事件、内部和外部模块)

笔记来自<Node入门>@2011 Manuel Kiessling JavaScript与Node.js Node.js事实上既是一个运行时环境,同时又是一个库. 使用Node.js时,我们不仅仅在实现一个应用,同时还实现了整个HTTP服务器. 一个基础的HTTP服务器 server.js:一个可以工作的HTTP服务器 var http = require("http"); http.createServer(function(request, response) { r

Node.js学习笔记(3) - 简单的curd

这个算是不算完结的完结吧,前段时间也是看了好久的Node相关的东西,总想着去整理一下,可是当时也没有时间: 现在看来在整理的话,就有些混乱,自己也懒了,就没在整理,只是简单的记录一下 一.demo的简单介绍 这次demo,只涉及到简单的curd操作,用到的数据库是mongo,所以要安装mongo数据库,数据库连接驱动是mongoose: 当然关于mongo的驱动有很多,比如mongous mongoskin等:(详见http://cnodejs.org/topic/4f4ca8e0940ce2e

系列文章--Node.js学习笔记系列

Node.js学习笔记系列总索引 Nodejs学习笔记(一)--- 简介及安装Node.js开发环境 Nodejs学习笔记(二)--- 事件模块 Nodejs学习笔记(三)--- 模块 Nodejs学习笔记(四)--- 与MySQL交互(felixge/node-mysql) Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识 Nodejs学习笔记(七)--- Node.js + Exp

Node.js学习笔记【3】NodeJS基础、代码的组织和部署、文件操作、网络操作、进程管理、异步编程

一.表 学生表 CREATE TABLE `t_student` ( `stuNum` int(11) NOT NULL auto_increment, `stuName` varchar(20) default NULL, `birthday` date default NULL, PRIMARY KEY  (`stuNum`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 学生分数表 CREATE TABLE `t_stu_score` ( `id` int(11

node.js学习笔记目录

1.node.js学习笔记(1)--Node.js简介及环境安装 2.node.js学习笔记(2)--使用Express快速创建应用 3.node.js学习笔记(3)--Express创建的项目分析 4.node.js学习笔记(4)--使用Express完成简单的登陆 5.node.js学习笔记(5)--MongoDB下载及安装 6.node.js学习笔记(6)--MongoDB简单入门 7.node.js学习笔记(7)--Node.js与MongoDB简单交互 8.node.js学习笔记(8)

node.js学习笔记(1)——什么是node.js?

什么是node.js? nodejs是编写高性能网络服务器的JavaScript工具包(用于js开发服务端程序) 单线程.异步.事件驱动 特点:快,耗内存多 网上一个百万级的并发测试,未优化的情况下消耗16G内存,原因在于其单线程轮询过后的事件异步处理,每一个异步事件开辟一块内存区域. node.js vs php 优点: 性能高(机制问题) 开发效率高(省不少优化的事) 应用范围广,可以开发桌面系统,electron框架 缺点: 新,人少 中间件少 IDE不完善 node.js的劣势和解决方案

node.js 学习笔记

学习网站:http://www.nodejs.net/a/20141016/232139.html: 笔记:介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏览器就基于V8,同时打开20-30个网页都很流畅.Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低.非常适合小型网站,个性化网站,我们自己的Geek网

node.js学习笔记(一)——创建第一个应用

巧妇难为无米之炊.要学习node.js,当然必须先有node.js环境(可以去官网 http://nodejs.cn/ 下载安装),如果还是不懂怎么配置开发环境,度娘会告诉你一切. 安装完成环境之后,先别急着开发.在开发之前,为了更清晰的掌握接下来我们的第一个应用的代码逻辑,我们还需要了解一下node.js 应用的基本组成成分,如下: 1. 引入 required 模块:我们可以使用 require 指令来载入 Node.js 模块. 2. 创建服务器:服务器可以监听客户端的请求,类似于 Apa