进程和线程
- 进程:一个程序(应用)「例如 饭店」
- 线程:程序中具体干活的「例如 服务员」
一个进程中可能包含多个线程!!
浏览器中新打开一个页卡,就相当于开辟一个新的“进程”,在这个进程中,包含多个“线程”
浏览器是多线程的
- GUI渲染线程「渲染HTML/CSS,最后绘制出相应的页面」
- JS引擎线程「俗称:主线程 渲染和解析JS代码的」
- HTTP网络线程「从服务器端,基于HTTP网络,获取相应的资源;同源下最多允许开辟 5~7 个HTTP线程」
- 定时器监听线程「监听定时器是否到时间」
- 事件监听线程「监听事件是否触发」
- …
但是,JS代码的渲染是单线程的,因为浏览器只分配一个“JS引擎线程”用来渲染解析JS代码!!
所谓的“同步”或者“异步”编程,主要就是由线程多少来决定的!
同步:
只有一个线程,同时只能干一件事情,上一件事情没有做完,此线程空闲不下来,那么后续的事情都做不了
异步:
具备多个线程,可以同时干很多事情
- 因为JS代码的渲染是单线程的,所以在JS中大部分代码都是“同步”的,例如:循环…
但是因为浏览器是多线程的,所以在JS中还有部分代码是“异步”的,例如:
「异步宏任务」
定时器
- requestAnimationFrame
- ajax/fetch
- 事件绑定
-
「异步微任务」
Promise
- Async/Await
- IntersectionObserver
- queueMicrotask
- …
虽然JS中有异步的代码,但是和传统的多线程异步操作还不太一样
- 所有JS代码的执行,都必须交给“主线程”去执行
- 所借用的浏览器线程,仅仅是帮助我们监听定时器是否到时间、监听事件是否触发…但是最后代码的执行,还是要交给主线程去执行的
这样的异步编程处理机制,需要一套完善的运作体系 —-> EventLoop 事件循环机制
练习题
setTimeout(() => {
console.log(1)
}, 20)
console.log(2)
setTimeout(() => {
console.log(3)
}, 10)
console.log(4)
for (let i = 0; i < 90000000; i++) {
// do soming
}
console.log(5)
setTimeout(() => {
console.log(6)
}, 8)
console.log(7)
setTimeout(() => {
console.log(8)
}, 15)
console.log(9)
定时器是异步操作
// 定时器即便设置等待时间是零,也不是同步代码,绑定的callback也不会立即执行
// 它也是异步的操作,按照EventLoop机制处理!!
setTimeout(() => {
console.log('A')
}, 0)
console.log('B')//-->'B' 'A'
死循环也会导致异步操作不执行
// 在JS中的任何位置都不要出现死循环,即便是在其他的异步操作中
// 不能论是同步还是异步,代码都是交给主线程渲染,如果死循环,则主线程被一直占用,后续所有的事情都无法处理!!
console.log(1)
setTimeout(() => {
console.log(2)
while (1) { }
}, 10)
console.log(3)
setTimeout(() => {
console.log(4)
}, 500)
console.log(5)