

## 异步编程

### 异步操作

- Node 采用 Chrome V8 引擎处理 JavaScript 脚本。V8 最大特点就是**单线程运行**，一次只能运行一个任务。

- Node 大量采用异步操作（asynchronous operation），即任务不是马上执行，而是插在任务队列的尾部，等到前面的任务运行完后再执行。

- 提高代码的响应能力。


异步IO也叫非阻塞IO。例如读文件，传统的语言，基本都是读取完毕才能进行下一步操作。非阻塞就是Node的callback，不会影响下一步操作，等到文件读取完毕，回调函数自动被执行，而不是在等待。

### 异步操作回调

由于系统永远不知道用户什么时候会输入内容，所以代码不能永远停在一个地方。

Node 中的操作方式就是以异步回调的方式解决无状态的问题。


### 回调函数的设计：错误优先

异步操作中，无法通过 try catch 捕获异常。

这是因为回调函数主要用于异步操作，当回调函数运行时，前期的操作早结束了，错误的执行栈早就不存在了，传统的错误捕捉机制try…catch对于异步操作行不通，所以只能把错误交给回调函数处理。

**统一约定：**

回调函数的第一个参数默认接收错误信息，第二个参数才是真正的回调数据（便于外界获取调用的错误情况）：

```
foo1('赵小黑', 19, function(error, data) {
  if(error)  throw error;
  console.log(data);
});
```


### 异步回调的问题

相比较于传统的代码：

- 异步事件驱动的代码

- 不容易阅读

- 不容易调试

- 不容易维护

另外还有个问题是**回调地狱：**

```javascript
do1(function() {
  do2(function() {
    do3(function() {
      do4(function() {
        do5(function() {
          do6()
        });
      });
    });
  });
});

```


## 进程和线程

### 进程（进行中的程序）

- 每一个 **正在运行** 的应用程序都称之为进程。

- 每一个应用程序运行都至少有一个进程。

- 进程是用来给应用程序提供一个运行的环境。

- 进程是操作系统为应用程序分配资源的一个单位。


### 线程

- 用来执行应用程序中的代码

- 在一个进程内部，可以有很多的线程

- 在一个线程内部，同时只可以干一件事

- 传统的开发方式大部分都是 I/O 阻塞的，所以需要多线程来更好的利用硬件资源。

线程并不是越多越好。

### 多线程的弊端

缺点一：

	- 创建线程耗费。
	- 线程数量有限。
	- CPU 在不同线程之间转换，有个上下文转换，这个转换非常耗时。

所谓的多线程其实都是假的，对于单核CPU而言，它们无非是在抢占 CPU 资源。线程和线程之间需要**切换和调度**，这是很耗费资源的。

缺点二：

- 线程之间共享某些数据，同步某个状态都很麻烦。

就算 CPU 是多核的，现在的问题是，线程与线程之间如果要共享数据，该怎么办？比如 A 线程要访问 B 线程的变量。



## 事件驱动和非阻塞机制


参考链接：<https://www.kancloud.cn/revin/nodejs/176211>


总结：

- Node 中将所有的阻塞操作交给了内部线程池实现。

- Node 主线程本身，主要就是不断的**往返调度**。


### 平台实现差异


由于 Windows 和 *nix 平台（其他平台）的差异，Node 提供了 libuv 作为抽象封装层，保证上层的 Node 与下层的自定义线程池及 IOCP 之间各自独立。

如下图所示：

![](http://img.smyhvae.com/20180301_2252.png)




