异步IO、事件驱动、单线程构成了node的基调。为什么异步IO在node中如此重要?先说一下异步的概念。异步在前端开发中很常见,比如ajax异步请求资源。如果前端页面同步请求资源,当我们请求资源时,代码会一直阻塞到IO请求结束。那么用户就会发现页面卡顿,点击事件等无效,这无疑会造成用户的流失。还有在运行服务端代码的时候,如果我们的程序是同步的,那么对于客户端的请求,它会一个一个的响应,这样后面的请求就会等待很长时间。这种场景下可以使用多线程并行执行,但是多线程编程的缺点是创建线程和切换线程上下文代价高昂,并且面临状态锁和状态同步等问题。使用异步IO操作,避免主线程阻塞,高效利用cpu。node给出的解决方案是单线程的,远离线程锁,状态同步问题。使用异步IO使单线程远离阻塞并有效地利用cpu。异步IO和非阻塞IO经常放在一起。实际上,它们是两个不同的概念。以上是异步IO。那么什么是阻塞IO和非阻塞IO呢?阻塞IO操作是指IO操作发起后,线程阻塞等待IO完成,期间无法有效利用CPU。非阻塞IO操作其实就是在IO操作发起后,通过事件巡逻或者事件通知机制不断查询IO操作是否完成,或者主线程进入睡眠等待事件通知结束的IO,然后继续向下执行代码。blockingIO期间,无论CPU是用来查询还是休眠,都没有得到有效利用。其实node的异步IO就是用到了线程池技术。当发起异步IO时,将io操作丢入线程池执行,然后主线程继续执行其他操作。io执行完成后,通过线程间通信通知主线程。主线程执行回调。另外,nix平台和windows平台下实现异步io的方案也不尽相同。nix下,node使用自己的线程池来模拟异步io,而windows下,则使用IOCP来实现异步io。由于平台的不同,为了兼容不同的平台,node封装了libuv层。节点异步IO模型异步调用发起异步调用封装请求对象,然后给请求对象添加回调函数,将请求对象放入线程池等待线程池执行IO操作时线程池线程可用,并将结果添加到request对象中通知iocpIO完成,返回线程事件循环创建循环,Tick获取完成的IO给IO观察器从IO观察器获取可用对象,使用回调对象的方法将对象上的结果作为参数,执行回调循环从IO观察器获取可用对象,并获取完成的IO并加入IO观察器。当没有可用对象时,退出循环。请求对象、观察者、事件循环、线程池构成了node的异步IO模型
