js事件循环(event loop)
认识进程和线程
-
进程(工厂):正在进行的程序,是操作系统独立运行的一个个体,系统需要给其分配资源(cpu、内存)。
-
线程(车间):是操作系统独立运行任务的最小单位。
执行多任务的时候,cpu会在多个线程间做着快速的切换。
- 电脑是多进程的。可以运行多个程序
- 浏览器是多线程的,意味可以同时运行多个任务。
- 浏览器包含的线程:
- UI渲染线程:负责解析html和css,绘制页面
- js引擎(单线程): 负责解析js代码
- 事件线程:单击事件onclick
- 网络线程: 网络请求-ajax
- 时间器线程: 定时器(setTimeIntval)和延时器(setTimeout)
- ....
以上除了js引擎线程,其他线程都是web浏览器提供的Api,统称为webApi。
注意:UI渲染线程和js引擎线程是互斥的,即不能同时运行
js为什么要成设计单线程的?
主要与js功能有关。最开始js是运行在浏览器端的。如果设计成多线程的话,一个线程增加DOM节点,另一个线程删除DOM节点,这样就容易造成冲突。
JS引擎是单线程
- 只有一个调用栈(call stack)
- 同一时刻只能做一件事。前面的事没做完,后面就要等着。
但调用栈中遇到了一些耗时的任务如时间器、网络请求等操作,浏览器会启用相应的线程去处理它。
这些耗时的任务我们称之为异步任务。
注意:时间器设置的时间只是理论上中最短的等待时间。
任务队列
- 所有异步任务的回调(cb),最终都会放入到任务队列中等待执行。
- 队列特点:先进先出,后进后出。 即先进来的任务先执行,后进来的任务后执行。
队列分类:
- 宏任务队列。如 script(整个代码区) ajax、fetch、setTimeout ...
- 微任务队列。如 then、...
若程序中有同步任务和异步任务,执行顺序为:
先同后异,先微后宏。 即先执行完所有的同步代码,剩下的异步代码按照先微后宏的顺序执行。
事件循环过程
script代码区就是一个最大的宏任务。
执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
理解事件循环
由于因为js引擎是单线程的,即只有一个调用栈,即同一时刻只能干一件事件。
如调用栈中遇到了比较耗时的任务,会由浏览器开启其他线程去处理这个耗时的任务,最后把这些异步任务的回调放入到任务队列中,等待排队执行。
当调用栈中的任务执行完毕之后,会从任务队列中取出下一个任务放在调用栈中执行,执行完后再取出下一个任务执行,循环往复此过程,这就是事件循环。