forked from theluyuan/Web
143 lines
3.5 KiB
Markdown
143 lines
3.5 KiB
Markdown
|
||
|
||
## 异步编程
|
||
|
||
### 异步操作
|
||
|
||
- 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 之间各自独立。
|
||
|
||
如下图所示:
|
||
|
||
20180301_2252.png
|
||
|
||
|
||
|
||
|
||
##
|
||
|
||
|
||
|