一、node.js简介
1.node.js是采用谷歌浏览器/V8引擎/C++编写的/JS运行环境. 2.可以解析JS代码(没有浏览器安全级的限制) 提供系统级别的API:1、文件的读写;2、进程的管理;3、网络通信二、为何学习node.js
1、nodejs.org看看nodejs的版本升级,新特性的加入,重要bug的修复等 2、www.npmjs.com模块社区,看他人源代码,省力 3、github.com大量的项目和源码 4、stackoverflow.com技术解答社区以及查询相关资源,环境配置,异常均可找到答案三、NodeJS、NPM安装配置步骤(windows版本)
参见:http://blog.csdn.net/aaa333qwe/article/details/75643372
偶数版本是稳定版本,奇数版本不稳定。
稳定的版本api功能不会发生变化,固定,
而奇数版本的会在后续的api文档中进行修改
四、node.js和浏览器执行环境对比
相同点:都能执行一般的Js代码
不同点:全局变量不同,例如window,document等只能在浏览器中取到,而process则只能在node环境中取到。
宿主:浏览器、node;
全局变量:浏览器-window、document;node - process;
nodejs 本质是一个js的执行环境 由于封装和底层的处理赋予了更大的能力
五、npm模块与包管理工具
js的天生缺陷——缺少模块化管理机制 问题: JS中容易出现变量被覆盖,方法被替代的情况(既被污染)。特别是存在依赖关系时,容易出现错误。这是因为JS缺少模块管理机制,来隔离实现各种不同功能的JS判断,避免它们相互污染。 解决方案: 经常采用命名空间的方式,把变量和函数限制在某个特定的作用域内,人肉约定一套命名规范来限制代码,保证代码安全运行。jQuery中有许多变量和方法,但是无法直接访问,必须通过jQuery,$调用 各个方法。Commonjs不同于jQuery,Commonjs是一套规范,约定了js如何组织,如何编写。大部分标准在拟定和讨论之中,首先把执行不同任务的代码块和代码文件看为独立的模块,每一个模块都是一个单独的作用域,但不是孤立的,可能存在依赖关系。每个模块分为三个部分,定义、标识和引用。这套规范与现实产品如node.js相互影响,良性循环。【Commonjs规范】
【NodeJs的模块管理机制】nodejs基于commonjs实现了模块管理系统。node中每一个js文件都是一个独立的模块,在其内部不需要有命名空间,不需要担心变量的污染和方法定义时的隔离。同时模块之间可以组合形成更强大的模块或功能包。npm即是用来管理各种功能包的。
六、node.js的模块分类
模块分为三类:1、核心模块(核心模块会在Node启动时预先加载):http ,fs, path。。。 2、本地模块(文件模块):var util = require('./util.js'); 3、第三方模块(通过npm安装):var promise = require('bluebird');备注:名称引用非核心模块时node.js会把文件名映射到对应的模块引用的路径。包含核心函数的核心模块在node启动时预先加载,非核心以及第三方模块之后加载。
模块的流程: 1、创建模块(一个入口的JS文件,里面加入一些特定的功能) teacher.js 2、导出模块(把功能和文件(即模块名)建立关系;是不是把模块的方法暴露出去?) exports.add=function(){} 3、加载模块(在其他的文件里面引入并加载这个模块,在nodejs里面使用require来完成这个工作) var teacher=require('./teacher.js') 4、使用模块(直接调用模块中命名好的方法) teacher.add('Scott')module.exports是真正的接口,exports只不过是它的辅助工具,是指向module.exports的引用。 模块可以是任何你设置给它的东西(任何合法的javascript对象--boolean, number, date, JSON, string, function, array等等)。 如果你没有显式的给Module.exports设置任何属性和方法,那么你的模块就是exports设置给Module.exports的属性。module.export和export的区别:5、querystring 的用法:1. module.exports 初始值为一个空对象 {} 2. exports 是指向的 module.exports 的引用 3. require() 返回的是 module.exports 而不是 exports如果你想要的模块是一个特定的类型就用Module.exports。 如果你想要的模块是一个典型的“实例化对象”就用exports。 推荐使用exports导出,除非你打算要一个类型而不是一个“实例化对象”module exports的区别 export是module的子集 当export和module含有相同的属性的时候module会覆盖exports的属性七、URL网址解析
4、url.resolve(from, to):将一个基本URL和指定超链接目标URL合并url 解析 定位所寻资源1、未传入参数,默认为false,即query解析为字符串
url.parse("http://www.imooc.com:8080/video/6710.html?name=sunqun&age=28#aaaaaaa")
Url {
protocol: 'http:', 指定底层使用的协议
slashes: true, 协议双斜线
auth: null,
host: 'www.imooc.com:8080', 服务器域名
port: '8080', 端口
hostname: 'www.imooc.com', 主机名
hash: '#aaaaaaa', 哈希值(通常是页面锚点)
search: '?name=sunqun&age=28', 查询字符串参数
query: 'name=sunqun&age=28', 发给http服务器的数据(通常等号分隔开的键值叫参数串)
pathname: '/video/6710.html', 访问资源路径名
path: '/video/6710.html?name=sunqun&age=28', 路径
href: 'http://www.imooc.com:8080/video/6710.html?name=sunqun&age=28#aaaaaaa' 未解析的超链接
}2、传入第二个参数true,可以让query解析为对象,默认为false,即query解析为字符串url.parse("http://www.imooc.com:8080/video/6710.html?name=sunqun&age=28#aaaaaaa", true) Url { protocol: 'http:', 指定底层使用的协议 slashes: true, 协议双斜线 auth: null, host: 'www.imooc.com:8080', 服务器域名 port: '8080', 端口 hostname: 'www.imooc.com', 主机名 hash: '#aaaaaaa', 哈希值(通常是页面锚点) search: '?name=sunqun&age=28', 查询字符串参数 query: { name: 'sunqun', age: '28' }, 发给http服务器的数据(通常等号分隔开的键值叫参数串) pathname: '/video/6710.html', 访问资源路径名 path: '/video/6710.html?name=sunqun&age=28', 路径 href: 'http://www.imooc.com:8080/video/6710.html?name=sunqun&age=28#aaaaaaa' 未解析的超链接 }3、url.format(一串对象格式字符串):将对象格式字符串解析成一个完整的网址
(1)、querystring.stringify(obj,sign1,sign2) //将对象转化成url中query部分的形式(序列化)参数:1.要转化的对象 2.链接符(默认&)3.键与值之间的符号(默认=) (2)、querystring.parse(string,sign1,sign2,sign3) //将query字符串转化成对象(反序列华)参数:1.query字符串 2.链接符(默认&)3.键与值之间的符号(默认=)4.参数的个数(默认最多1000个,0就没有限制) (3)、querystring.escape(string) //文字转译 (4)、querystring.unescape(string) //反转译八、HTTP相关的知识点
参见:http://blog.csdn.net/aaa333qwe/article/details/77407962
九、搭建http服务器
var http = require('http') http.creatServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}) res.write('hello world!!!') res.end() }) .listen(2016)
在仓库主页,按t,即可呼出仓库搜索的面板搜索http.js,进行源码解析:
调用createServer实际上是返回Server实例,createServer里面的回调函数(参数requestListener)直接作为了Server的参数requestListener 而这个Server实际上是require('_http_server') _http_server.js下: fuction Server(requestListener)里面实际上是为这个requestListener函数与'request'事件绑定到了一起 而'request '是方法parserOnIncoming里面抛出的一个事件,见488行self.emit('request'.req,res);这个事件也会同时抛出req和res两个对象 关于req与res两个变量: 其中,428行可知req变量与另一个叫做shouldKeepAlive的变量作参同时传入此函数parserOnIncoming 而,由437行可见res变量是new ServerResponse(req)出来的实例 见101行可见ServerResponse的定义,再由函数体内部113行知此函数继承自OutgoingMessage 见37行: var outgoingMessage = require('_http_outgoing').OutgoingMessage; _http_outgoing.js下 67行为function OutgoingMessage的定义 见93行OutgoingMessage继承自Stream即为一个流的子类 由函数体内部67-91行可知此函数里面初始化的各种变量全是跟服务器返回的内容有关的东西 最终可得出res实际上是一个ServerResponse,而ServerResponse是一个Stream,这个Stream里面全是各种服务器返回的各种内容属性(见_http_outgoing.js里的67-91行啊啊)十、HTTP性能测试
十二、 HTTP事件模块Apache的ab的用法是: ab [options] [http://]hostname[:port]/path ab ([options])常用参数的介绍: -n :总共的请求执行数,缺省是1 -c: 并发数,缺省是1 -t:测试所进行的总时间,秒为单位,缺省50000s -p:POST时的数据文件 -w: 以HTML表的格式输出结果在window系统下,需要先用cd命令定位到你的apache安装目录的bin文件夹。。。并且我在powershell中运行的,需要打成.\ab才能运行。。。。$ ab -n1000 -c10 http://www.imooc.com/十一、HTTP小爬虫(慕课网)参见:http://blog.csdn.net/aaa333qwe/article/details/77413603
Events a.EventEmitter支持多个事件监听,最大为10,也可以自定义最大数 //添加监听 var EventEmitter = require('events').EventEmitter; var instance = new EventEmitter(); instance.on('event',function(arguments){});
b.如果超过十个也能执行,不过有可能会造成内存泄漏 //自定义最大数 //每个setMaxListeners针对的是一个特定事件:即event1,event2,... 默认最大都为10,本例为num instance.setMaxListeners(num); c.事件监听之后,需要emit(发射,发出)才会执行 instance.emit('event',arguments) d.判断是否监听 boolean instance.emit('event',arguments) //true or false e.移除监听事件 //移除单个事件监听 instance.removeListener('event',funcName) //移除事件需具名函数,匿名函数不行 //移除多个事件监听 instance.removeAllListerner() //不传参表示移除所有事件监听 instance.removeAllListerner('event') //移除特定event的所有事件监听 f.计算事件监听数量 //第一种 instance.listeners('event').length //第二种 EventEmitter.listenerCount(instance,'event')完整示例源码:
var EventEmitter = require('events').EventEmitter;
var life = new EventEmitter();
life.setMaxListeners(11);
function water(who){
console.log('给'+who+'倒水')
}
life.on('求安慰', water)
life.on('求安慰', function(who){
console.log('给'+who+'做饭')
})
life.on('求安慰', function(who){
console.log('给'+who+'揉肩')
})
life.on('求安慰', function(who){
console.log('给'+who+'洗衣服')
})
life.on('求安慰', function(who){
console.log('给'+who+'....5')
})
life.on('求安慰', function(who){
console.log('给'+who+'....6')
})
life.on('求安慰', function(who){
console.log('给'+who+'....7')
})
life.on('求安慰', function(who){
console.log('给'+who+'....8')
})
life.on('求安慰', function(who){
console.log('给'+who+'....9')
})
life.on('求安慰', function(who){
console.log('给'+who+'....10')
})
life.on('求安慰', function(who){
console.log('给'+who+'....11')
})
life.on('求溺爱', function(who){
console.log('给'+who+'买衣衣')
})
life.on('求溺爱', function(who){
console.log('给'+who+'交工资')
})
life.removeListener('求安慰',water);
life.removeAllListeners('求安慰');
var hasconfortListener = life.emit('求安慰','汉子');
var hasLoveListener = life.emit('求溺爱','妹子');
var hasPlayedListener = life.emit('求玩坏','妹子和汉子');
console.log(life. listeners('求安慰').length);
console.log(EventEmitter.listenerCount(life, '求溺爱'));
console.log(hasconfortListener);
console.log(hasLoveListener)
console.log(hasPlayedListener)
十三、http的request请求
http的get和request可以从后台发起一个http的请求,从而可以获取远程的资源,从而更新和同步远程的资源。request接收两个参数,一个是options,一个是回调函数callback(回调函数是一个可选的参数,可加可不加),通过回调函数可以接收到远端服务器的使用术语,也就是response,第一个参数可以是一个字符串(若是字符串,会通过URL的parse方法解析为一个对象),也可以是一个对象。如果第一个参数是对象的话就可以进行一系列的配置,来定制我们需要发出的请求格式。上图就罗列了比较常用的参数,比如host等。这么多的参数其实不是每一个都要传递,大部分是默认的,我们传递的就是主机、端口、请求头和论证。 网站视频举例:用request()进行技术灌水。 对于某个网站(如慕课网)来说,一个请求是否合法、是否符合要求,就要看请求的路径对不对,然后请求头Header的信息能不能对应得上。 http.get()方法与 http.request() 唯一的区别是它设置请求方法为 GET 且自动调用 req.end()。
参数:
HTTP - get / request http的api里面get就是对request的封装, get能做的request都能做 http.request(options,[callback]) host:主机名 hostname:host别名 port: 端口号(8080) localAddress:绑定本地连接的接口 method: http请求的字符串(get) path:请求的根路径 / headers:请求头的对象 auth:计算认证头的基本认证 agent:控制agent行为 keepAlive:保存资源池周围套接字在未来能继续用于其他请求(false)完整示例代码:
var http = require('http'); var querystring = require('querystring'); var postData = querystring.stringify({ 'content': '一起期待后面的课程' }); var options = { hostname: 'www.zhihu.com', port: 80, path: '/api/v4/answers/187041525/comments', method: 'post', headers: { 'accept' : 'application/json, text/plain, /*', 'Accept-Encoding' : 'gzip, deflate, br', 'Accept-Language' : 'zh-CN,zh;q=0.8', 'authorization' : 'Bearer Mi4wQUlBQVZXanJOQW9BUUVJRTZiZTRDeGNBQUFCaEFsVk5IWTExV1FEZ2VDOS1lcjk5c2JweE5IbDlxUFZ0MngtTVB3|1498284061|fdcbe4756a5be8618e5496ec368f0015f418bc59', 'Cache-Control' : 'no-cache', 'Connection' : 'keep-alive', 'Content-Length' : postData.length, 'content-type' : 'application/json', 'Cookie' : 'd_c0="AEBCBOm3uAuPTs8mW72ljw7vwrnM0VmNRTw=|1494154802"; _zap=5dea2d08-5a01-4d2c-8ba9-94bb5b7c5699; q_c1=1d579f5664084e58a1129050ac5de926|1498284057000|1494154801000; r_cap_id="N2E1YWVhNjQ2YzI1NDRjZGJjMjMxOTM4Y2IwNWY5YTQ=|1498284057|3a90cc1fa24050e97e6c055a7a8cffba0f08c708"; cap_id="ZGRjNmIxZDhiMTUyNGM5ZDhmMjIzNzNlMzkzNDhjMTM=|1498284057|a9f2f942e38c7122a8f017c0708ea2d5d9ccd22c"; z_c0=Mi4wQUlBQVZXanJOQW9BUUVJRTZiZTRDeGNBQUFCaEFsVk5IWTExV1FEZ2VDOS1lcjk5c2JweE5IbDlxUFZ0MngtTVB3|1498284061|fdcbe4756a5be8618e5496ec368f0015f418bc59; __utma=51854390.381729045.1494154799.1496570324.1498284055.4; __utmz=51854390.1494154799.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmv=51854390.100--|2=registration_date=20160710=1^3=entry_date=20160710=1; aliyungf_tc=AQAAAEDS2zBnHAkApu93fZOKuFLk4mUx; _xsrf=d6fbb7c3-84a0-4081-a434-5495922c5598', 'Host' : 'www.zhihu.com', 'Origin' : 'https://www.zhihu.com', 'Pragma' : 'no-cache', 'Referer' : 'https://www.zhihu.com/', 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36', 'x-udid' : 'AEBCBOm3uAuPTs8mW72ljw7vwrnM0VmNRTw=', 'x-xsrftoken' : 'd6fbb7c3-84a0-4081-a434-5495922c5598', } } var req = http.request(options, function(res){ console.log('status' + res.statusCode); console.log('headers' + JSON.stringify(res.headers)); res.on('data', function(chunk){ console.log(Buffer.isBuffer(chunk)); console.log(typeof chunk); }) res.on('end', function(){ console.log('评论完毕!'); }) }) req.on('error', function(e){ console.log('Error: ' + e.message); }) req.write(postData); req.end();