上一节我们几乎是扫通http请求和响应的整个闭环,包括请求时候的头信息和服务器返回时候的头信息和状态码等等,这些在node的http中
都能获取到,并且有相应都接口组装这些信息和返回它们,同时这些http接口被设计的时候,就考虑了可以支持许多http协议的特性,而这
些特性在传统的开发中却很难使用,比如大体积的块编码的消息,除这以外,为了让用户可以在请求和响应中可以使用流的形式操作数据,
接口从不缓存请求和响应,那么整套http,api都很底层,他只处理流相关的操作以及信息解析,可以把信息解析成请求头和请求体,但并不
实际解析请求头和请求正文里面的具体内容,这个就是nodejs中关于node http模块的介绍
什么是回调
回调是异步编程最基本的方法,对于nodejs来说需要按顺序执行异步逻辑的时候,一般采用后续传递的方式,也就是将后续逻辑封装
在回调函数中作为起始函数的参数,逐层去嵌套,通过这种方式让程序通过我们所期望的方式走完整个流程
具名函数
function learn(something){ console.log(something); } function we(callback, something){ something += ' is cool'; callback(something); }
we(learn,'Nodejs')
匿名函数
function we(callback, something){ something += ' is cool'; callback(something); } we(function(something){ console.log(something); }, 'Jade')
什么是同步/异步
对应异步就是同步,举个例子,打电话给饭店老板有没有空位可以预约,如果是同步执行机制呢,老板会说,等我去查一查,然后就开始
查查查,可能一分钟,可能两分钟,可能五分钟,再告诉你结果,这就是打电话,查结果,拿到结果,挂电话,组合在一起,就是完整的顺序
的执行,总结起来就是,同步就是执行一个任务,后一个任务等待前一个任务结束然后再执行,程序的执行顺序与任务的排列顺序是一致的,对
于我们来说,放到浏览器里面更容易理解,浏览器端的js是单线程的,因此js代码只能按顺序执行,即使js文件可以并行的下载,也在按顺序
执行,如果一个js文件里面有个死循环这样耗时的代码,那么页面就会被阻塞在这段代码,后面的文件就不会被执行到,
{/* <script src='a.js'></script> <script src='b.js'></script> <script src='c.js'></script> */} var a = 0; while(true){ a++; }
假设b里面有这样到一段阻塞代码,后面c就不会执行
那么异步呢就会完全不同,还是刚才那个例子,打电话给老板,老板会说,我查一下,我查好之后打电话给你,然后就直接挂电话了,查好了
以后,他会主动把电话打给你,这个时候老板是通过回电话这种方式来回调,那么这个就是打电话,留下号码,挂电话,再查结果,回电话,
最后拿到结果,每个任务都有一个,或者多个回调函数,前一个任务执行完之后不是执行后一个任务,而是执行回调函数,后一个任务也不是等待
前一个任务执行结束后执行,程序的执行顺序与任务的排列顺序是不一致的,是异步的,那么js这门语言里面,最基础的异步函数就是setTimeout
和setInterval,setTimeout会在一定的时间后执行一定的函数,他接受一个回调函数,作为第一个参数,还接受一个ms的时间,作为第二个
参数
var c = 0; function printC(){ console.log(c); } function add(){ setTimeout(function(){ c+=1; },1000) } add(); printC();
打印出来的是0,不是所期望的1,那这个时候怎么办呢,我们可以把这个plus改造一下,
var c = 0; function printC(){ console.log(c); } function add(callback){ setTimeout(function(){ c+=1; callback(); },1000) } add(printC);
这样就是打印我们所期望的结果,就是1
什么是单线程/多线程
什么是单线程,跟单线程对应的就是多线程,举个不太恰当,但是比较暴力的一个例子,比如谈对象,一次只能谈一个,谈了一年分手了
再谈下一个,再分手,再谈下一个,自己本身就是一个单线程,之前的那个没分手,这个就不能弹,就算你喜欢的也不能弹,每次只能弹一个人
大概就这么个意思,然后回到程序中,程序的功能是按照顺序执行的,只有前面的流程都成功以后,后面都流程才能被执行到,再具体一点,回到
js这门语言到代码层面,代码是按顺序执行到,并且一次只能执行某一段代码,这一段代码执行以后,才能执行下一段代码,那么谈对象,这个
没分手,又谈了一个,这叫什么,行业俗语叫,脚踏两只船,体现在程序里面呢,就是多线程。谈了好几个女盆友,每一个都相安无事,也还好,
但是呢,也有sb的时候,同一时间,陪谁过,这个时候,就会出现争抢资源,就分身乏术,一不小心,就崩溃了,这个时候多线程就有了分配
和管理资源的难度,那么单线程的特点就是,一次只能谈一个女朋友,但是安全,不断的分,不断的谈,一段时间以后,说不定比多线程谈女盆友
还多,但是前一个女朋友,不同意分手,一直追着你,那也可能导致下一个女盆友永远也谈不到,那你就被阻塞到这里了,总结起来一句话,单线程
一次只能谈一个女朋友,她到全部就是我的全部,多线程呢,允许脚踏多只船,只要能够分配好资源,无论是多线程还是单线程,都有他发挥威力
的场景,都有各自短板的地方,
什么是i/o
磁盘的写入和读出,数据的进和出,在nodejs里面本质就是为文件系统,数据库等资源提供接口,向文件系统发送一个请求的时候,不用
等待硬盘,等硬盘准备好的时候,非阻塞接口会通知到node
什么是阻塞/非阻塞
如果是阻塞的方式,在打电话的时候,会把自己挂起,等待等待等待,直到有座位的这样一个结果,如果是非阻塞式呢,你电话一挂,不管
老板有没有告诉你,你自己就玩去了,跑步,看电影,该干啥干啥,当然也可以过几分钟来个电话催一下,确认老板有没有搞定
什么是事件,什么是事件驱动,什么是基于事件驱动的回调
在nodejs里面回调什么时候被调用呢,这个时候就要讲一讲事件了,比如在浏览器里面点击是一个事件,拖拽窗口,也是一个事件,
function clickIt(e){ alert('button is clicked'); } var btn = document.getElementById('#btn'); btn.addEventListener('click', clickIt);
那么通过上面几句代码实现了一个事件,点击btn,弹出一个框,那么在nodejs里面很多对象都会触发事件,比如,server每次在客户端连接
到他的时候会触发事件,比如读取文件,打开一个文件的时候也会触发一个事件,那么所有可以触发的事件都是events下面的EventEmitter实例,
关于这个EventEmitter,后面再讲,像这种为了某个事件注册了回调函数,但是这个回调函数不是马上执行,只有这个事件发生的时候才会调用
回调函数,这种函数执行的方式就叫事件驱动,这种注册回调,就是基于事件驱动的回调,如果这些回调跟异步的io操作有关,那这就可以看做是
基于异步回调的io,只不过这种回调在nodejs里面是由事件来驱动的,
什么是事件循环
event loop,倘若说有大量的异步操作,以及io的耗时操作,甚至是一些定时器控制的延迟操作,他们完成的时候都会去调用响应
的回调函数,从而来完成一些密集的任务,而又不会阻塞整个执行的流程,这个时候,这么多事件,就需要一个机制来管理,这种机制就是
事件循环,event loop是一个回调函数队列,当异步函数执行的时候,回调函数就会被压入到这个队列,对于nodejs来说,通过不断的
查询,队列中是否有事件,等到读取到这个事件到时候,调用这个事件关联到js函数,事件循环是先进先出到任务队列,回调就会按照被
加入队列到顺序来执行,整个队列可以看成一个普通到函数和一个回调函数构成的一个完整的队列
了解完这些才能够去理解,nodejs的核心思想,也就是非阻塞,单线程,和事件驱动,而这些看上去很虚的一些概念,可以帮助我们很好的去
理解下一节的内容