coderwwh w:
what是什么? w:why为什么? h:how怎么样?
事件循环是什么?
是:JS代码和浏览器(或node)之间的桥梁
参考coderwhy老师的图
知识补充:进程和线程
是什么
- 进程:计算机已经运行的程序
- 线程:操作系统能够运行调度的最小单元
- 进程:我们可以认为,启动一个应用程序,就会默认启动一个进程(也可能是多个进程);
- 线程:每一个进程中,都会启动一个线程用来执行程序中的代码,这个线程被称之为主线程;
- 所以我们也可以说进程是线程的容器
多进程多线程开发
浏览器和js
我们知道js是单线程的,但是 Javascript 的线程应该有自己的容器进程:浏览器或者 Node
浏览器是多进程的,一个tab是一个进程,防止一个卡死
每个进程又有很多线程,其中包括js线程
但是js是单线程的,意味着
- js在同时只能做同一件事
- 如果这件事十分耗时,当前线程会被阻塞
浏览器的事件循环
每一个回调函数就是一个任务,是宏任务,加到宏任务任务队列里
- ajax
- settimeout
- dom监听
- 。。。
promise.then产生的回调加入微任务任务队列(还有其他的)
- promise.then
- mutation Observer API
- queueMicro
- 。。。
微任务 > 宏任务
执行完一个宏任务队列后,不会再下一个宏任务,会判断在该宏任务执行过程中有没有新微任务产生,如果有,先执行微任务,再执行下一个宏任务
测试
阻塞IO与非阻塞IO
思考:JavaScript可以直接对一个文件进行操作吗?
看起来是可以的,但是事实上我们任何程序中的文件操作都是需要进行系统调用(操作系统的文件系统)
事实上对文件的操作,是一个操作系统的系统调用(IO系统是输入、输出);
操作系统通常为我们提供了两种调用方式:
阻塞式调用和非阻塞式调用:
-
阻塞式调用:调用结果返回之前,当前线程处于阻塞态(阻塞态CPU是不会分配时间片的),调用线程只有在得到调用结果之后才会继续执行。
-
非阻塞式调用:调用执行之后,当前线程不会停止执行,只需要过一段时间来检查一下有没有结果返回即可。
非阻塞IO问题
非阻塞IO也会存在一定的问题:我们并没有获取到需要读取(我们以读取为例)的结果
意味着为了可以知道是否读取到了完整的数据,我们需要频繁的去确定读取到的数据是否是完整的;
这个过程我们称之为轮训操作;
谁来操作
这个轮训的工作由谁来完成呢?
如果我们的主线程频繁的去进行轮训的工作,那么必然会大大降低性能;
并且开发中我们可能不只是一个文件的读写,可能是多个文件;
而且可能是多个功能:网络的、数据库的、子进程调用;
libuv提供了一个线程池(Thread Pool):
线程池会负责所有相关的操作,并且会通过轮训或者其他的方式等待结果
当获取到结果时,就可以将对应的回调放到事件循环(某一个事件队列)中
事件循环就可以负责接管后续的回调工作,告知JavaScript应用程序执行对应的回调函数
阻塞和非阻塞)区别(同步和异步)
阻塞和非阻塞是对于被调用者来说的
在我们这里就是系统调用,操作系统为我们提供了阻塞调用和非阻塞调用
同步和异步是对于调用者来说的
在我们这里就是自己的程序
如果我们在发起调用之后,不会进行其他任何的操作,只是等待结果,这个过程就称之为同步调用
如果我们再发起调用之后,并不会等待结果,继续完成其他的工作,等到有回调时再去执行,这个过程就是异步调用
node里的事件循环
stream
一连串的字节
在之前学习文件的读写时,我们可以直接通过readFile或者writeFile方式读写文件,为什么还需要流呢?
直接读写文件的方式,虽然简单,但是无法控制一些细节的操作;
比如从什么位置开始读、读到什么位置、一次性读取多少个字节;
读到某个位置后,暂停读取,某个时刻恢复读取等等;
或者这个文件非常大,比如一个视频文件,一次性全部读取并不合适;
文件读写的stream
//流的方式读取
const reader = fs.createReadStream("./foo.txt", {
start: 3,
end: 6,
highWaterMark: 2
))
reader.on("data", (data) => {
console.log(data);
})