根据这里整理所得
问题点
当前 Web Server 处理一个请求时多数时间被消耗在等待磁盘I/O及网络延迟上
解决方案
比较传统的解决方法是:程序员在编码时开一个新的线程来处理需要消耗大量等待时间的操作。但这样带来的问题是更加程序复杂性度,对程序员编码不友好。Node 通过基于事件轮询的回调机制来解决该问题。
Node.js 事件轮询
当程序调用了一段非阻塞的操作时,Node 在低层开一个新的线程与主线程同时运行,一旦该隐藏线程的操作处理完成后,会将所得结果交由相应的回调函数处理。Node 通过 libuv 库来处理异步 I/O 线程的调度问题。
任务队列
javascript 是一种单线程、事件驱动的语言。所以需要通过事件的监听这种方式来处理多任务。即当事件被触发时,程序调用事前提供的回调函数来处理该事件。而这些回调函数本身也能通过队列来处理多任务。
但我们只有一个主线程和一个回调栈,所以一个任务的回调函数需要等待执行栈为空(即无任务--阻塞代码在执行)的时候才能执行,从而形成了一个任务队列。当主线程完成它的上一个任务时,可执行的回调函数(如果有)总会被调起,如此循环往复,故称为事件轮询。
微任务和大任务
Node 中包含两种任务队列来分别存放两种类型的任务。
微任务包括:process.nextTick
, promises
, Object.observe
大任务包括:setTimeout
, setInterval
, setImmediate
, I/O
基于 WHATVG 规范,事件轮询的一个周期只处理大任务队列中的一个大任务。在这个周期内,当大任务处理完成后,他下面微任务列表中可执行的微任务才可以依次执行。只有当该微任务队列中的可执行的微任务执行完后,事件轮询才可以进入下一个周期。
最后
在 async/await 尚未成为标准之前可通过 co 或者 koa 来处理异步操作的 callback hell 问题,当然也可以通过 async.js 来解决。