美文网首页Js让前端飞Web 前端开发
Javascript 基础夯实——理解 Event Loop、M

Javascript 基础夯实——理解 Event Loop、M

作者: ac68882199a1 | 来源:发表于2017-07-23 10:11 被阅读121次

    首先就标题上的三个名词做个名词解释:)

    Event Loop:事件循环
    Micro Task:微任务
    Macro Task:宏任务

    所以这次的主体呼之欲出:理解 Javascript 中的事件循环、微任务与宏任务机制

    在开始本文之前,小伙伴们可以先去看之前的一篇文章,在这篇文章中略微提及了本篇所述的内容:

    前端面试题——深入探究 setTimeout

    Tasks & Stack

    Javascript 中的事件循环是以任务为单位的,将很多个待执行的任务串联在一起就形成了队列Task Queue,很多的队列先后按顺序执行任务就形成了Event Loop,所以要理解 Event Loop,就需要先了解 task 的执行过程,请看下图:

    Micro Task

    我们知道调用alert时会阻塞页面的渲染,其实这是因为渲染页面总是在任务队列全部执行结束后才会开始,用示意图表示如下:

    那么 Micro Task 又是什么执行呢?Micro Task 也是在任务队列执行结束后才执行(或者栈为空时),但是却会先于渲染页面,它就像一条挂在任务队列后面的小尾巴匆匆执行完自己的任务,但是如果这条小尾巴太过繁重,也会影响到页面的渲染

    Micro Task 会维护一条自己的队列,同样也存在入栈和出栈的操作

    那么有哪些操作是 Micro Task 呢?Promise 就是其中之一

    Macro Task

    Marco Task 会在当前所有的任务全部执行结束后执行,也就是说,如果当前存在渲染页面,Marco Task 会在页面渲染结束之后执行,所以 Macro Task 不会导致页面的阻塞

    我们常用的setTimeout 就是 Macro Task,同时setImmediate 等也是,这也是我们总是将alert写在setTimeout中的原因

    举例论证:)

    function func1 () {
        console.log('func 1')
    }
    function func2 () {
        console.log('func 2')
    }
    function func3 () {
        console.log('func 3')
    }
    function func4 () {
        console.log('func 4')
    }
    
    const func = function () {
        func1()
        setTimeout(func2, 0)
        Promise.resolve().then(
            () => func3()
        )
        func4()
    }()
    

    上面一串代码执行后,在控制台会按如下顺序打印出以下内容:

    func1
    func4
    func3
    func2
    

    其实根据上文的内容很容易就能够推断出打印内容的顺序,但是我们依然对其进行从入栈和出栈的角度分析一下

    // 任务队列
    // 开始时无任务
    task queue: []
    
    // micro task queue
    micro queue: []
    
    // macro task queue
    macro queue: []
    
    // 栈
    stack: []
    

    执行立即执行函数funcfunc入栈:

    task queue: [func]
    micro queue: []
    macro queue: []
    stack: [func]
    

    执行func1时,func1入栈:

    task queue: [func, func1]
    micro queue: []
    macro queue: []
    stack: [func, func1]
    

    func1执行结束,出栈:

    task queue: [func]
    micro queue: []
    macro queue: []
    stack: [func]
    

    setTimeout进入 marco task,不执行其回调:

    task queue: [func]
    micro queue: []
    macro queue: [setTimeout]
    stack: [func]
    

    promise进入 micro task,不执行其回调

    task queue: [func]
    micro queue: [promise]
    macro queue: [setTimeout]
    stack: [func]
    

    执行func4并入栈:

    task queue: [func, func4]
    micro queue: [promise]
    macro queue: [setTimeout]
    stack: [func, func4]
    

    func4执行结束并出栈:

    task queue: [func]
    micro queue: [promise]
    macro queue: [setTimeout]
    stack: [func]
    

    func执行结束并出栈:

    task queue: []
    micro queue: [promise]
    macro queue: [setTimeout]
    stack: []
    

    此时 stack 已空,任务全部执行结束,开始执行 micro task promiseThen

    task queue: []
    micro queue: [promise]
    macro queue: [setTimeout]
    stack: [promiseThen]
    

    promiseThen执行结束出栈:

    task queue: []
    micro queue: []
    macro queue: [setTimeout]
    stack: []
    

    如果需要重新渲染页面的话,则会在此时执行,如果不需要,则开始执行 macro tasksetTimeoutCallback

    task queue: []
    micro queue: []
    macro queue: [setTimeout]
    stack: [setTimeoutCallback]
    

    setTimeoutCallback执行结束出栈:

    task queue: []
    micro queue: []
    macro queue: []
    stack: []
    

    以上就是这个简单的例子的任务执行顺序

    Event Loop

    看到这里,你应该已经知道 Event Loop 是什么了,上面的例子是 Event Loop 中的一条,而执行完这一整条之后,还会有下一条,下下条,它们在一起就组成了完整的 Event Loop 机制,周而复始不断循环

    当然,关于 Event Loop 的解释并不只有这一种,但是本质上都是相同的,micro task 和 macro task 会区别于 主任务 / 主线程 的队列,并且在程序的整个生命周期中不停的重复 主任务 ——> micro task ——> 渲染视图 ——> macro task 的操作

    最后再厚颜无耻的求下关注:)

    扫码关注前端周记公众号

    相关文章

      网友评论

        本文标题:Javascript 基础夯实——理解 Event Loop、M

        本文链接:https://www.haomeiwen.com/subject/slgpkxtx.html