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开发指南》
(未完待续,欢迎指出错误)
Node.js学习笔记(4)——除了HTTP(服务器和客户端)部分的更多相关文章
- Node.js学习笔记 01 搭建静态服务器
希望这篇文章能解决你这样一个问题:“我现在已经了解了一些Node.Js基本概念了,怎么搭一台静态服务器呢?” 请参考一下博主的前两篇文章: 完全面向于初学者的Node.js指南 Node.Js的Mod ...
- 一点感悟:《Node.js学习笔记》star数突破1000+
写作背景 笔者前年开始撰写的<Node.js学习笔记> github star 数突破了1000,算是个里程碑吧. 从第一次提交(2016.11.03)到现在,1年半过去了.突然有些感慨, ...
- Node.js学习笔记(2):基本模块
Node.js学习笔记(2):基本模块 模块 引入模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在No ...
- Node.js学习笔记(1):Node.js快速开始
Node.js学习笔记(1):Node.js快速开始 Node.js的安装 下载 官方网址:https://nodejs.org/en/ 说明: 在Windows上安装时务必选择全部组件,包括勾选Ad ...
- Node.js学习笔记(3):NPM简明教程
Node.js学习笔记(3):NPM简明教程 NPM常用操作 更新NPM版本 npm install npm -g -g,表示全局安装.我们可以指定更新版本,只需要在后面填上@版本号即可,也可以输入@ ...
- 系列文章--Node.js学习笔记系列
Node.js学习笔记系列总索引 Nodejs学习笔记(一)--- 简介及安装Node.js开发环境 Nodejs学习笔记(二)--- 事件模块 Nodejs学习笔记(三)--- 模块 Nodejs学 ...
- Node.js学习笔记(4):Yarn简明教程
Node.js学习笔记(4):Yarn简明教程. 引入Yarn NPM是常用的包管理工具,现在我们引入是新一代的包管理工具Yarn.其具有快速.安全.可靠的特点. 安装方式 使用npm工具安装yarn ...
- Node.js学习笔记(一)基础介绍
什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...
- Node.js学习笔记(2) - Node.js安装及入门hello world
今天来简单的记录一下Node.js的安装配置以及简单的入门 一.Node.js的安装 1.windows下的安装 windows下的安装很简单,只需要去官网http://nodejs.org中,找到w ...
- Node.js学习笔记(六) --- Nodejs 的非阻塞 I/O、 异步、 事件驱动
1. Nodejs 的单线程 非阻塞 I/O 事件驱动在 Java. PHP 或者.net 等服务器端语言中,会为每一个客户端连接创建一个新的线程.而每个线程需要耗费大约 2MB 内存.也就是说,理论 ...
随机推荐
- Php中常见的4种随机密码生成方法详解
使用PHP开发应用程序,尤其是网站程序,常常需要生成随机密码,如用户注册生成随机密码,用户重置密码也需要生成一个随机的密码.随机密码也就是一串固定长度的字符串,这里我收集整理了几种生成随机字符串的方法 ...
- 【01】npm/cnpm安装
包安装相关信息: 1.node_modules文件夹 node_modules文件夹在nodejs中是一个特殊的文件夹,通过它的名字就可以看出,该文件夹也是用于存放node模块.如果一个模块表达式不是 ...
- Unity使用 16bit 压缩 Texture 颜色能均匀过渡
下面是unity自带 16bit 图 的效果,可以看到颜色过度的很不均匀,占用内存 0.5M 如果调成 truecolor 后 颜色过渡很均匀,而内存却占到 1.1 M 讲图片 后缀名改成 ...
- RazorExtensions Templated Razor Delegates
原文发布时间为:2011-04-27 -- 来源于本人的百度文章 [由搬家工具导入] Templated Razor Delegates David Fowler turned me on to a ...
- 用.net开发wap
原文发布时间为:2010-08-19 -- 来源于本人的百度文章 [由搬家工具导入] .NET 模板:http://download.csdn.net/source/2631001 WAP应用程序结构 ...
- 《30天学习30种新技术》-Day 15:Meteor —— 从零开始创建一个 Web 应用
目录:https://segmentfault.com/a/1190000000349384 原文: https://segmentfault.com/a/1190000000361440 到目前为止 ...
- s 中日期 转换成时间戳 例如2013-08-30 转换为时间戳
以前遇到过一个关于时间戳的问题,为了不被大家鄙视,先说一下概念. 具体时间戳怎么定义的我也不清楚,但百度百科中有这么一句:“时间戳是自 1970 年 1 月 1 日(00:00:00 GMT)至当前时 ...
- CF501D Misha and Permutations Summation(康托展开)
将一个排列映射到一个数的方法就叫做康托展开.它的具体做法是这样的,对于一个给定的排列{ai}(i=1,2,3...n),对于每个ai求有多少个aj,使得j>i且ai>aj,简单来说就是求a ...
- js-Flexbox盒子布局
这个年轻的时候,我在项目中其实很少用到: 现在老了,发现了他的好处,我就开始慢慢用到了: 但是其实我对他还是不熟悉的,很陌生,在此做个笔记,加油
- 搭建https本地服务器:如何得到被所有客户端认可的ssl证书
https,作为http的加密版,作用还是很大的:能够提升网站搜索权重,让你的网站更安全,而且如果你的网站没有使用https的话,将无法作为移动设备原生应用的api接口.可见掌握为网站启用https的 ...