JavaScript事件循环机制

作者: 一蓑烟雨任平生_cui | 来源:发表于2019-09-27 18:01 被阅读0次
    1. js是单线程的,该线程中有唯一一个事件循环,任务队列可以有多个

    2. JavaScript代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)来搞定另外一些代码的执行。


      队列数据结构
    3. 任务队列: 宏任务和微任务

    • 宏任务:script(整体代码)、setTimeout、setInterval、setImmediate、(I/O、UI rendeing这俩没研究)
    • 微任务:Promise、Node中的process.nextTick、html5新特性MutationObserver(没研究)
    1. setTimeout/Promise等我们称之为任务源(任务分发器)。而进入任务队列的是他们指定的具体执行任务。
    2. 来自不同任务源的任务会进入到不同的任务队列。其中setTimeout与setInterval是同源的。
    3. 其中每一个任务的执行,无论是macro-task还是micro-task,都是借助函数调用栈来完成。

    关于setImmediate:MDN解释

    1. 该特性是非标准的,请尽量不要在生产环境中使用它!
    2. 该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数。
    3. 注意: 该方法可能不会被批准成为标准,目前只有最新版本的 Internet Explorer 和Node.js 0.10+实现了该方法。它遇到了 Gecko(Firefox) 和Webkit(Google/Apple) 的阻力。

    浏览器执行

    console.log('global1')
    
    setTimeout(() => {
        console.log('setTimeout1')
        new Promise(resolve => {
                console.log('p1')
                resolve()
            })
            .then(() => {
                console.log('p1-then')
            })
    
        new Promise(resolve => {
                console.log('p2')
                resolve()
            })
            .then(() => {
                console.log('p2-then')
            })
    })
    
    setTimeout(() => {
        console.log('setTimeout2')
    
        new Promise(resolve => {
                console.log('p3')
                resolve()
            })
            .then(() => {
                console.log('p3-then')
            })
    })
    
    new Promise(resolve => {
            console.log('p5')
            resolve()
        })
        .then(() => {
            console.log('p5-then')
        })
    
    console.log('global2')
    

    输出顺序:

    // global1 p5 global2 p5-then setTimeout1 p1 p2 p1-then p2-then setTimeout2 p3 p3-then
    

    浏览器执行机制:

    1. script (这个过程中执行同步代码,宏任务加入相应类型的队列,微任务加入相应类型的队列)
    2. 执行清空所有微任务
    3. 执行第一个加入队列的宏任务 setTimeout (setImmediate的任务队列会在setTimeout队列的后面执行),并将该过程中产生的微任务加入相应的队列
    4. 执行清空所有微任务
    5. 执行第二个宏任务

    ...

    以此类推,以一宏任务---所有微任务的顺序交替执行

    Node执行

    console.log('global1')
    
    setImmediate(() => {
        console.log('setImmediate1')
        new Promise(resolve => {
                console.log('p1')
                resolve()
            })
            .then(() => {
                console.log('p1-then')
            })
    })
    
    setTimeout(() => {
        console.log('setTimeout1')
        new Promise(resolve => {
                console.log('p2')
                resolve()
            })
            .then(() => {
                console.log('p2-then')
            })
    
        new Promise(resolve => {
                console.log('p3')
                resolve()
            })
            .then(() => {
                console.log('p3-then')
            })
    })
    
    setTimeout(() => {
        console.log('setTimeout2')
    
        new Promise(resolve => {
                console.log('p4')
                resolve()
            })
            .then(() => {
                console.log('p4-then')
            })
    
        process.nextTick(() => {
            console.log('process1')
        })
    })
    
    new Promise(resolve => {
            console.log('p5')
            resolve()
        })
        .then(() => {
            console.log('p5-then')
        })
    
    process.nextTick(() => {
        console.log('process2')
    })
    
    console.log('global2')
    

    Node输出:

    // global1 p5 global2 process2 p5-then setTimeout1 p2 p3 setTimeout2 p4 process1 p2-then p3-then p4-then setImmediate1 p1  p1-then
    

    Node执行机制:

    1. 同浏览器
    2. 执行清空所有微任务 (执行微任务时,nextTick队列会比Promie先执行。nextTick中的可执行任务全部执行完毕之后,才会开始执行Promise队列中的任务。)
    3. 执行某一类(某一队列)宏任务(先执行完所有setTimeout宏任务,将该过程产生的微任务加入相应队列)
    4. 执行清空所有微任务
    5. 执行另一队列宏任务 setImmediate

    ...
    以此类推,以一(队列)宏任务---所有微任务的顺序交替执行。

    任务队列和函数调用栈

    相关文章

      网友评论

        本文标题:JavaScript事件循环机制

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