Nodejs 中的同步与异步、阻塞与非阻塞
最近在微信读书上读一本国内讲Nginx的书,里面提到异步,同步,阻塞和非阻塞,然后里面的用户笔记乱解释,还一大堆人给他点爱心,所以现在连辩解错误的能力都没有了么?
在学习Nodejs的过程中,经常会听到同步异步,阻塞和非阻塞。那什么是异步什么是同步呢?什么是阻塞和非阻塞?
Nodejs是单线程的异步事件驱动的Js运行时,使用事件循环的方式,将操作交给系统内核处理,当操作完成后内核通知Nodejs讲合适的回调函数添加到轮询队列中等待回调执行。而阻塞,在官方教程中也有说明
阻塞 是指在 Node.js 程序中,其它 JavaScript 语句的执行,必须等待一个非 JavaScript 操作完成。这是因为当 阻塞 发生时,事件循环无法继续运行 JavaScript。
在 Node.js 中,JavaScript 由于执行 CPU 密集型操作,而不是等待一个非 JavaScript 操作(例如 I/O)而表现不佳,通常不被称为 阻塞。在 Node.js 标准库中使用 libuv 的同步方法是最常用的 阻塞 操作。原生模块中也有 阻塞 方法。
在 Node.js 标准库中的所有 I/O 方法都提供异步版本,非阻塞,并且接受回调函数。某些方法也有对应的 阻塞 版本,名字以
Sync
结尾。
很明显可以看出,所谓的非 JavaScript 操作既不是ES中规定的API操作。所以像for循环,数值计算,这种并不算是阻塞。而标准库中所有的Sync
方法是非 JavaScript 操作操作,会阻塞主线程的JS代码运行。
在Nodejs中,我们常听到异步回调,到底什么是异步回调?在js中,回调是通过执行传入的方法,既等到操作执行完,会通过回调方法通知。既然有异步回调也会有同步回调。
1 |
|
同步既执行顺序与代码编写顺序相符的。而异步则是执行顺序与代码编写顺序不符。但是同步回调可直接写成下面这样子,所以一般同步回调使用的场景几乎没有。
1 |
|
那看看异步回调是怎么样的。
1 |
|
其中readFile
的第二个参数就是异步回调方法。虽然叫异步回调方法,但是也是在主线程执行的,毕竟事件轮询调用这个回调方法是用来通知主线程的。
非阻塞方法需要异步回调方法通知主线程,阻塞方法直接阻塞Js主线程。阻塞和非阻塞都为非 JavaScript 操作,JavaScript 操作不能成为阻塞和非阻塞。
因为非阻塞需要异步回调函数通知主线程,当一个操作流程需要一连串的IO和网络操作,并且这些IO和网络操作都需要严格按照一定执行时,就会出现回调地狱。为了解决这个问题,人们给异步回调披上Promise
的外衣,实现了链式调用,把异步回调用then
的方式执行,把多行代码压成一行。但是依然不如同步代码一样看起来直观,所以人们有给Promise
装一个箱子,就是async
和await
。