什么是回调?
回调是异步编程的基础方法,当须要按照顺序执行异步逻辑的时候,通常采起后续传递的方式,也就是将后续逻辑封装在回调函数中做为起始函数的参数,逐层去嵌套。node
function lean(something){ console.log(something) } function we(callback,something){ something+=' is cool' callback(something)//结果传递给回调函数 } we(lean,'node')//具名函数 we(function(something){//传递匿名函数 console.log(something) },'jade')
什么是同步
同步就是执行一个任务,后一个任务等待前一个任务结束,而后再执行,程序执行的顺序与任务的排列顺序是一致的,好比js是单线程的,所以js代码是按照顺序执行的,即使是js同步下载多个文件,也得按照顺序执行,一旦js里面出现死循环的代码,那么页面就会被阻塞在这个地方,后面的js代码就不会被执行到 好比打电话预定座位,发现没有座位了,店员就挂电话开始查找有没有座位,查找,查找...等待一下子以后,店员经过回电话,开始执行回调函数来解决你的问题(是否有座位)。
什么是异步
异步执行任务,若是发现任务阻塞,js执行setTimeOut,毫秒时间做为其中的一个参数,而后自动执行另一个函数,不会一直等待。数据库
//代码按照顺序执行,结果看就是1 var c = 0 function printIt(){ console.log(c) } function plus(){ c+=1 } plus() printIt()
//加上耗时操做,没有加回调函数,结果不改变 var c = 0 function printIt(){ console.log(c) } function plus(){//加上耗时操做,没有调用回调函数,因此js一直阻塞在这里,不能执行,因此结果仍是 0,没有变化。 setTimeout(function(){ c+=1 },1000) } plus() printIt()
var c = 0 function printIt(){ console.log(c) } function plus(callback){ setTimeout(function(){ c += 1 callback();//5s以后timeout,开始调用回调函数 },5000) } plus(printIt)
什么是io
磁盘的写和读,在nodejs里面就是为文件系统,数据库资源提供接口,发送请求的时候,不用等待硬盘,当硬盘准备好了,非阻塞接口就会通知处理
什么是阻塞/非阻塞
阻塞,在电话预约座位的时候,你将本身挂起,等待...直到等到有座位的信息的时候才挂电话。
非阻塞,打电话预约座位,没有等店员回答你是否有结果,你就挂电话了,该干啥干啥。你也能够过几分钟过来催一下,看看店员有没有搞定。
什么是事件
点击,拖拽等都是事件
什么是事件驱动
有事我叫你,没事别烦我--当须要的时候才会被调用。
事件循环
主线程从"任务队列"中读取事件,这个过程是循环不断的,因此整个的这种运行机制又称为Event Loop(事件循环)。
上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各类外部API,它们在"任务队列"中加入各类事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。
Node.js的Event Loop
Node.js也是单线程的Event Loop,可是它的运行机制不一样于浏览器环境。
根据上图,Node.js的运行机制以下。编程
(1)V8引擎解析JavaScript脚本。 (2)解析后的代码,调用Node API。 (3)libuv库负责Node API的执行。它将不一样的任务分配给不一样的线程,造成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。 (4)V8引擎再将结果返回给用户。
除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与"任务队列"有关的方法:process.nextTick和setImmediate。它们能够帮助咱们加深对"任务队列"的理解。浏览器
process.nextTick方法能够在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")以前----触发回调函数。也就是说,它指定的任务老是发生在全部异步任务以前。setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务老是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。请看下面的例子(via StackOverflow)。缓存
process.nextTick(function A() { console.log(1); process.nextTick(function B(){console.log(2);}); }); setTimeout(function timeout() { console.log('TIMEOUT FIRED'); }, 0) // 1 // 2 // TIMEOUT FIRED
上面代码中,因为process.nextTick方法指定的回调函数,老是在当前"执行栈"的尾部触发,因此不只函数A比setTimeout指定的回调函数timeout先执行,并且函数B也比timeout先执行。这说明,若是有多个process.nextTick语句(无论它们是否嵌套),将所有在当前"执行栈"执行。异步
如今,再看setImmediate。异步编程
setImmediate(function A() { console.log(1); setImmediate(function B(){console.log(2);}); }); setTimeout(function timeout() { console.log('TIMEOUT FIRED'); }, 0);
上面代码中,setImmediate与setTimeout(fn,0)各自添加了一个回调函数A和timeout,都是在下一次Event Loop触发。那么,哪一个回调函数先执行呢?答案是不肯定。运行结果多是1--TIMEOUT FIRED--2,也多是TIMEOUT FIRED--1--2。函数
使人困惑的是,Node.js文档中称,setImmediate指定的回调函数,老是排在setTimeout前面。实际上,这种状况只发生在递归调用的时候。oop
setImmediate(function (){ setImmediate(function A() { console.log(1); setImmediate(function B(){console.log(2);}); }); setTimeout(function timeout() { console.log('TIMEOUT FIRED'); }, 0); }); // 1 // TIMEOUT FIRED // 2
上面代码中,setImmediate和setTimeout被封装在一个setImmediate里面,它的运行结果老是1--TIMEOUT FIRED--2,这时函数A必定在timeout前面触发。至于2排在TIMEOUT FIRED的后面(即函数B在timeout后面触发),是由于setImmediate老是将事件注册到下一轮Event Loop,因此函数A和timeout是在同一轮Loop执行,而函数B在下一轮Loop执行。spa
咱们由此获得了process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句老是在当前"执行栈"一次执行完,多个setImmediate可能则须要屡次loop才能执行完。事实上,这正是Node.js 10.0版添加setImmediate方法的缘由,不然像下面这样的递归调用process.nextTick,将会没完没了,主线程根本不会去读取"事件队列"!
process.nextTick(function foo() { process.nextTick(foo); });
事实上,如今要是你写出递归的process.nextTick,Node.js会抛出一个警告,要求你改为setImmediate。
另外,因为process.nextTick指定的回调函数是在本次"事件循环"触发,而setImmediate指定的是在下次"事件循环"触发,因此很显然,前者老是比后者发生得早,并且执行效率也高(由于不用检查"任务队列")。
Http缓存机制