简介
JS是一门单线程语言,因为它运行在浏览器渲染主线程中,而渲染主线程只有一个。而渲染主线程承担多个任务,渲染页面、执行JS都在其中运行。如果使用同步方式,可能会发生阻塞(例:遇到无法立即处理的任务定时器),导致消息队列中的很多任务无法执行。这样会导消耗主线程的时间,导致页面无法及时更新,给用户造成卡死的现象。所以浏览器采用异步方式避免,当某些任务发生时,比如计时器,网络,事件监听,主线程将任务交给其他线程处理,自身结束任务的执行,转而执行后续的代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。
JS为何阻塞渲染?
<template>
姓名:<span> {{ name }} </span>
<el-button @click="nameChange">
点击更换名称
</el-button>
</template>
const name=" ";
// 死循环指定的时间
const delay (duration) {
var start = Date.now();
while( Date.now()-start < duration ){}
}
// 点击
const click=()=>{
name.value="HELLO WORLD";
delay(3000)
}
结果:后才会执行渲染出"HELLO WORLD"
原因:因为在一个线程上需要排序执行
任务有优先级吗?
任务没有优先级,只能先进先出,但是消息队列有优先级。
- 每个任务都有一个任务类型,同一个类型的任务必须在队列,不同类型的任务可以分属于不同的队列。在一次事件循环中,浏览器可以根据实际情况从不同队列中取出任务执行。
- 浏览器必须准备好一个微队列(microtask queue),微队列中的任务优先所有执行。
目前chrome的实现中,至少包含下面的队列:
- 延迟队列:用于存放计时器到达后的回调任务,优先级【中】
- 交互队列:用于存放用户操作后产生处理任务,优先级【高】
- 微队列:用于用户存放需要最快执行的任务,优先级【最高】
添加任务到微队列主要方式是使用 Promise、MutationObserver
例如:函数放入微队列
Promise.resolve().then(函数)