什么是异步编程?
异步编程
- 今天我们来聊聊
异步编程
,究竟什么是异步编程
,什么由是同步编程
呢? - 其实
异步编程
可以用一句话来概括,那就是:程序无须按照代码顺序自上而下的执行
CPU
与存储器
- 我们要想了解
异步编程
就需要了解一下cpu
和存储器,了解程序运行过程中CPU
和存储器起到了什么作用或者说扮演了什么角色.
1. CPU
-
cpu
是中央处理器,计算机核心部件,负责运算和指令调用。开发者编写的JavaScript
代码在被编译为机器码以后就是通过CPU
执行的。
2. 存储器
内存
:用于临时存储数据
,断电后数据丢失。由于数据读写速度快,计算机中的应用都是在内存中运行的。磁盘
:用于持久存储数据
,断电后数据不丢失。内部有磁头依靠马达转动在盘片上读写数据, 速度比内存慢。计算机应用程序在没有运行时是存储在磁盘中的,当我们启动应用程序后,应用程序会被加载到内存中运行,应用程序中的指令会被中央处理器
CPU
来执行。
I/O
模型
- 从数据库中查询数据(将磁盘中的文件内容读取到内存中),由于磁盘的读写速度比较慢,查询内容越多花费时间越多。无论
I/O
操作需要花费多少时间,在I/O
操作执行完成后,CPU
都是需要获取到操作结果的,那么问题就来了,CPU
在发出I/O
操作指令后是否要等待I/O
操作执行完成呢 ? 这就涉及到I/O
操作模型了,I/O
操作的模型有两种。- 第一种是
CPU
等待I/O
操作执行完成获取到操作结果后再去执行其他指令,这是同步 I/O 操作
(阻塞 I/O
)。 - 第二种是
CPU
不等待I/O
操作执行完成,CPU
在发出I/O
指令后,内存和磁盘开始工作,CPU
继续执行其他指令。当I/O
操作完成后再通知CPU I/O
操作的结果是什么。这是异步 I/O 操作
(非阻塞 I/O
) 。 同步 I/O
在代码中的表现就是代码暂停执行等待 I/O 操作
,I/O 操作执行完成后再执行后续代码。异步 I/O
在代码中的表现就是代码不暂停执行
,I/O 操作后面的代码可以继续执行,当 I/O 操作执行完成后通过回调函数的方式通知 CPU,说 I/O 操作已经完成了,基于 I/O 操作结果的其他操作可以执行了 (通知 CPU 调用回调函数)。同步 I/O
和异步 I/O
区别就是是否等待 I/O 结果。
- 第一种是
Nodejs
采用的就是异步非阻塞 I/O
模型。
- 下面用一段代码展示:使用
node
内置模块先读取文档内容后,再输出Hello
// 调用node内置模块读取文件内容(fs模块) |
- 结果展示:(证明
node
是异步非阻塞的i/o模型
)
进程与线程
每当我们运行应用程序时,操作系统都会创建该应用程序的
实例对象
,该实例对象
就是应用程序的进程
,操作系统会按照进程为单位
为应用程序分配资源,比如内存,这样程序才能够在计算机的操作系统中运行起来。线程
被包裹在进程
之中,是进程中的实际运作单位
,一条线程指的就是进程中的一个单一顺序的控制流。也就是说,应用程序要做的事情都存储在线程之中。可以这样认为,一条线程就是一个待办列表
,供CPU
执行。
Node
中的JS
运行是 单线程 还是 多线程 ?
- 在
Node.js
代码运行环境中,它为JavaScript
代码的执行提供了一个主线程
,通常我们所说的单线程
指的就是这个主线程
,主线程
用来执行所有的同步代码
。但是Node.js
代码运行环境本身是由 C++ 开发的,在Node.js
内部它依赖了一个叫做libuv
的c++
库,在这个库中它维护了一个线程池
,默认情况下在这个线程池中存储了 4 个线程,JavaScript 中的异步代码就是在这些线程中执行的
,所以说JavaScript
代码的运行依靠了不止一个线程
,所以JavaScript
本质上还是多线程
的。
下面我们再聊聊js
中天生的异步语法
1. 基于回调函数
的异步编程
回调函数
是指通过函数参数的方式将一个函数传递到另一个函数中,参数函数
就是回调函数。我们经常将
回调函数
写成callback
,实际上它是call then back
的简写,含义是调用后返回
,就是在主函数中调用参数函数,参数函数调用完成后返回主函数继续执行主函数中的代码。在
异步编程
中,异步 API
执行的结果就是通过回调函数
传递参数的方式传递到上层代码中的。但是这种方法存在一个弊端,那就是回调地狱
// (1). 回调函数(callBack) |
2. 基于Promise
的异步编程
Promise
是JavaScript
中异步编程解决方案
,可以解决回调函数方案中的回调地狱问题。可以将
Promise
理解为容器,用于包裹异步API
的容器,当容器中的异步API
执行完成后,Promise
允许我们在容器的外面获取异步API
的执行结果,从而避免回调函数嵌套。Promise
翻译为承若,表示它承若帮我们做一些事情,既然它承若了它就要去做,做就会有一个过程,就会有一个结果,结果要么是成功要么是失败。所以在
Promise
中有三种状态, 分别为等待(pending)
,成功(fulfilled)
,失败(rejected)
。默认状态为等待,等待可以变为成功,等待可以变为失败。
状态一旦更改不可改变,成功不能变回等待,失败不能变回等待,成功不能变成失败,失败不能变成成功。
// (2). promise方法 |
async/await
异步函数解决异步编程
Promise
虽然解决了回调地狱的问题,但是代码看起来仍然不够简洁。使用
async/await
可以更加简化异步编程代码的编写async
声明异步函数的关键字,异步函数
的返回值会被自动填充到Promise
对象中。await
关键字后面只能
放置返回Promise
对象的API
。await
关键字可以暂停函数执行
,等待Promise
执行完后返回执行结果。await
关键字只能出现在异步函数中(只能出现在async
的里面,不能单独存在)。
// (3). async/await方法 |