3.2.chrome事件循环、异步api

642 阅读3分钟

事件循环EventLoop

  • 主线程: 事件循环,消费消息队列里的任务;
  • 消息队列:存储任务队列,支持添加和取出任务;
  • i/o线程、网络等异步api:生产任务到消息队列; image.png

微任务 vs 宏任务

  • 微任务包括 process.nextTickpromiseMutationObserver,其中 process.nextTick 为 Node.js 独有。
  • 宏任务包括 <script>setTimeoutsetIntervalsetImmediate,I/O ,UI rendering
  • javaScript 是单线程的语言,Chrome 通过引入事件循环机制来处理在线程运行过程中产生的新任务,通过消息队列来处理其它线程发过来的任务,渲染进程通过 IO 线程来接收整理其它进程传进来的消息。
  • 浏览器通过在宏任务中维护一个微任务队列来执行高优先级的任务,通过回调功能来解决单个任务执行时间过长导致阻塞的问题。
  • Event Loop 就是主线程从消息队列中循环不断的读取事件去执行的过程。
  • 在一个宏任务中,分别创建一个用于回调的宏任务和微任务,无论什么情况下,微任务都早于宏任务执行。

image.png

web api

1. 定时器

  在 Chrome 中除了正常使用的消息队列之外,还有另外一个消息队列,这个队列中维护了需要延迟执行的任务列表,包括了定时器和 Chromium 内部一些需要延迟执行的任务

2.XMLHttpRequest

由浏览器的其他进程或者线程去执行,然后再将执行结果利用 IPC 的方式通知渲染进程,之后渲染进程再将对应的消息添加到消息队列中。

image.png

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')

image.png

  • 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)
})

image.png