事件循环EventLoop
- 主线程: 事件循环,消费消息队列里的任务;
- 消息队列:存储任务队列,支持添加和取出任务;
- i/o线程、网络等异步api:生产任务到消息队列;
微任务 vs 宏任务
- 微任务包括
process.nextTick,promise,MutationObserver,其中process.nextTick为 Node.js 独有。 - 宏任务包括
<script>,setTimeout,setInterval,setImmediate,I/O ,UI rendering。 - javaScript 是单线程的语言,Chrome 通过引入事件循环机制来处理在线程运行过程中产生的新任务,通过消息队列来处理其它线程发过来的任务,渲染进程通过 IO 线程来接收整理其它进程传进来的消息。
- 浏览器通过在宏任务中维护一个微任务队列来执行高优先级的任务,通过回调功能来解决单个任务执行时间过长导致阻塞的问题。
- Event Loop 就是主线程从消息队列中循环不断的读取事件去执行的过程。
- 在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务执行。
web api
1. 定时器
在 Chrome 中除了正常使用的消息队列之外,还有另外一个消息队列,这个队列中维护了需要延迟执行的任务列表,包括了定时器和 Chromium 内部一些需要延迟执行的任务
2.XMLHttpRequest
由浏览器的其他进程或者线程去执行,然后再将执行结果利用 IPC 的方式通知渲染进程,之后渲染进程再将对应的消息添加到消息队列中。
3.requestAnimationFrame
requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘
window.requestAnimationFrame(callback)
4.MutationObserver
监听dom变化并及时做出响应
5.Promise
Promise 之所以要使用微任务是由 Promise 回调函数延迟绑定技术导致的。
function Bromise(executor) {
var onResolve_ = null
var onReject_ = null
//模拟实现resolve和then,暂不支持rejcet
this.then = function (onResolve, onReject) {
onResolve_ = onResolve
};
function resolve(value) {
//在调用到 onResolve_ 函数的时候,Bromise.then 还没有执行,需要延时
//Promise 把这个定时器改造成了微任务
//setTimeout(()=>{
onResolve_(value)
//},0)
}
executor(resolve, null);
}
function executor(resolve, reject) {
resolve(100)
}
//将Promise改成自定义的Bromsie
let demo = new Bromise(executor)
function onResolve(value){
console.log(value)
}
demo.then(onResolve)
6.Generator
生成器(Generator)函数是一个带星号函数,而且可以暂停和恢复执行,生成器就是协程的一种实现方式。
unction* genDemo() {
console.log("开始执行第一段")
yield 'generator 2'
console.log("开始执行第二段")
yield 'generator 2'
console.log("开始执行第三段")
yield 'generator 2'
console.log("执行结束")
return 'generator 2'
}
console.log('main 0')
let gen = genDemo()
console.log(gen.next().value)
console.log('main 1')
console.log(gen.next().value)
console.log('main 2')
console.log(gen.next().value)
console.log('main 3')
console.log(gen.next().value)
console.log('main 4')
- 1)通过调用生成器函数 genDemo 来创建一个协程 gen,创建之后,gen 协程并没有立即执行。
- 2)要让 gen 协程执行,需要通过调用 gen.next。
- 3)当协程正在执行的时候,可以通过 yield 关键字来暂停 gen 协程的执行,并返回主要信息给父协程。
- 4)如果协程在执行期间,遇到了 return 关键字,那么 JavaScript 引擎会结束当前协程,并将 return 后面的内容返回给父协程。
7.async/await
async/await 技术背后的秘密就是 Promise 和生成器应用,往低层说就是微任务和协程应用。
async function foo() {
console.log(1)
let a = await 100
console.log(a)
console.log(2)
}
console.log(0)
foo()
console.log(3)
当执行到await 100时,会默认创建一个 Promise 对象。
let promise_ = new Promise((resolve,reject){
resolve(100)
})