进程:
每个应用程序运行都需要一段内存空间,可以把这一块内存空间理解为进程
线程:
有了内存空间,一个进程会自动创建一个线程运行程序,线程负责运行程序,这个线程是主线程。一个程序里面,可能同时需要执行多段代码,主线程就会启动更多的线程。一个进程里面可以有多个线程。
浏览器进程和线程
浏览器是一个多进程多线程的程序。
- 浏览器进程
-主要负责和用户交互,界面显示,子进程管理等。比如用户的点击,滚动事件。浏览器进程内部会启动多个线程完成任务。 - 网络进程
-负责加载网络资源 - 渲染进程
浏览器的渲染进程开启之后。会开启一个渲染主线程,负责执行html,css,js代码。 默认情况下,一个标签页就是一个渲染进程。
渲染主线程的任务:
- 解析HTML
- 解析CSS
- 计算样式
- 布局
- 处理图层
- 每秒把页面画60次
- 执行全局js代码
- 执行事件处理函数
- 执行计时器的回调函数
事件循环
- 最开始的时候,渲染主线程会开启无限循环
- 每一次循环,都会判断消息队列中是否有任务存在,如果有,就执行取出第一个任务执行。执行完以后,进入下一次循环,没有的话,就会进入休眠状态。
- 其他所有线程可以随时向消息队列里面添加任务,新任务会加入消息队列的末尾。如果是休眠状态,会唤醒主线程,继续循环执行任务。 整个过程,就是事件循环(消息循环)
异步
代码在执行的过程中,会遇到一些无法立即执行的任务:
- 计时器完成后需要执行的任务
- 网络通信完成后需要执行的任务
- 用户操作后需要执行的任务**。
如果等待这些任务执行的时机到达,渲染主线程会处于阻塞状态,浏览器卡死。所以需要异步执行这些任务。 - 使用异步的方式,渲染主线程就不会阻塞
任务优先级
任务没有优先级,但是消息队列有优先级。过去就是微任务队列和宏任务队列。最新的W3c解释如下:
- 每个任务都有一种任务类型,相同类型的任务必须放在一个队列中,不同类型的任务放在不同的队列中。浏览器可根据实际情况选取队列执行任务。
- 浏览器必须准备好一个微任务队列,微任务队列中的任务优先其他所有任务执行。
- chrome浏览器:目前的主要队列:延时队列,用户交互队列,微任务队列。
js的异步理解
- js是一门单线程的语言。因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。
- 渲染主线程要执行很多任务,解析html,执行js等。
- 如果主线程采用同步的方式执行代码,可能会阻塞主线程的执行,导致消息队列中的其他任务无法执行。会浪费时间,以及导致页面无法及时更新卡死。
- 所以采用异步的方式去解决。当遇到一些异步的任务,渲染主线程将这些任务交给其他线程去处理,自身立即结束执行任务,执行后续代码。当其他线程完成,将事先传递的回调函数包装成任务,放入消息队列的末尾,等待主线程的调度执行。
- 在这种异步模式下,浏览器就不会阻塞,单线程也可以流畅运行。
Js的事件循环
事件循环又称之为消息循环,是浏览器渲染主线程的工作方式。 在chrome的源码中,它开启一个死循环,每次循环从消息队列中取出第一个任务执行,其他线程只需要在合适的时候把任务放入消息队列的末尾即可。 过去就是微任务队列和宏任务队列。目前的浏览器情况更加复杂,灵活的处理。 最新的W3c解释如下:
- 每个任务都有一种任务类型,相同类型的任务必须放在一个队列中,不同类型的任务放在不同的队列中。
- 不同的任务队列有不同的优先级
- 在一次事件循环中,浏览器可根据实际情况选取队列执行任务。
- 但是浏览器必须准备好一个微任务队列,微任务队列中的任务优先其他所有任务执行。必须优先调度。
Promise
promise.resolve.then(函数)的功能是:立即把这个函数放入微任务队列中
const promise = new Promise((resolve, reject) => {
console.log(1)
setTimeout(() => {
console.log('timerStart')
resolve('success')
console.log('timerEnd')
}, 0)
console.log(2)
})
promise.then((res) => {
console.log(res)
})
console.log(4)
输出顺序:1 2 4 timerStart timerEnd success(等这个宏任务执行完毕)
async 和 await
- await之前的代码是同步代码
- await 等待的一定是一个promise对象
- await 会暂停后面代码的执行,将其放入微任务队列中
async function async1() {
console.log('async1') 同步代码执行
await async2() 执行(等待返回一个promise对象,将promise。then的内容放入微任务队列)
console.log('async1 end') 暂停执行(等)
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeOut')
}, 0)
async1()
new Promise((resolve) => {
console.log('promise')
resolve()
}).then(() => {
console.log('promise2')
})
console.log('script end')
输出结果:
script start async1 async2 promise script end async1 end promise2 setTimeOut
执行顺序:
打印 script start
st推入宏任务
调用async1 函数 打印 async1 执行 async2 打印async2 就是这里会返回一个执行成功的promise 已经等到了 ,所以将 后续的放入微任务队列 微任务:aend
继续同步代码 打印promise 微任务:promise2 打印script end
微任务:处理 打印 async1 end promise2
宏任务 :打印 setTimeout