美文网首页
event loop

event loop

作者: 阿布朗迪 | 来源:发表于2019-06-24 13:38 被阅读0次

    前言

    最近一直在看基本知识点,发现自己的理解太过于偏颇、浅显加之记忆力不行,遂还是以文字的形式记录下来,这是缘由之一。当然,也希望通过这样的方式去整理逻辑,使之清晰。

    为什么会有event loop?

    和其他语言相比较,JavaScript语言特点就是单线程的。起初这门语言的设计主要用于与用户互动的,提高用户网页使用的体验度。然后渐渐发展成前端开发必不可少的语言。但是在实际的业务当中,开发人员发现单线程有太多的阻碍。这也是event loop产生的原因。

    什么是event loop

    主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制成为even loop。

    运行进制

    首先需要了解JavaScript的运行机制

    1. 所有同步任务都在主线程上执行,形成一个执行栈。
    2. 主线程之外,还存在“任务队列”。只要异步任务有了运行结果,就在“任务队列”之中放置一个事件。
    3. 一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是接收等待状态,进入执行栈,开始执行。
    4. 主线任务不断重复上面的第三步。

    再说even loop 运行进制。
    主线任务会不断从任务队列中按顺序去取任务执行,每执行完一个任务都会检查microtask队列是否为空,如果不为空则会一次性执行完所有的microtask。然后再进入下一个循环去任务队列中去下一个任务执行。

    具体如下:

    1. 当选择需要执行的宏任务队列,选择一个最先进入任务队列的宏任务,如果没有宏任务选择,则会跳转至microtask的执行步骤。
    2. 将事件循环的当前运行宏任务设置为已选择的宏任务。
    3. 运行宏任务。
    4. 将事件循环的当前运行任务设置为null。
    5. 将运行完的宏任务从宏任务队列中移除。
    6. microtask步骤:进入microtask检查点。
    7. 更新界面渲染。
    8. 返回第一步

    执行进入microtask 检查的具体步骤:

    1. 设置进入microtask检查点的标志位true
    2. 当事件循环的微任务队列不为空时,选择一个最先进入microtask队列的microtask;设置事件循环的当前运行任务为null,将运行结束的microtask从microtask队列中移除。
    3. 对于相应事件循环的每个环境设置对象,通知他们哪些promise为rejected.
    4. 清理indexDB的事务。
    5. 设置进入microtask检查点的标志为false。
    console.log('script start')
    
    setTimeout(function(){
        console.log('setTimeout --- 0')
    },0)
    
    setTimeout(function(){
        console.log('setTimeout --- 200')
        setTimeout(function(){
            console.log('inner -setTimeout --- 0')
        })
        Promise.resolve().then(function(){
            console.log('promise5')
        })
    },200)
    
    Promise.resolve().then(function(){
        console.log('promise1')
    }).then(function(){
        console.log('promise2')
    })
    
    Promise.resolve().then(function(){
        console.log('promise3')
    })
    console.log('script end')
    

    运行结果:
    script start

    script end
    promise1
    promise3
    promise2
    setTimeout --- 0
    setTimeout --- 200
    promise5
    inner -setTimeout --- 0

    分析:

    1. 首先顺序执行完主进程上的同步任务,第一句和最后一句的console.log
    2. 接着遇到setTimeout 0,它的作用是在 0ms 后将回调函数放到宏任务队列中(这个任务在下一次的事件循环中执行)。
    3. 接着遇到setTimeout 200,它的作用是在 200ms 后将回调函数放到宏任务队列中(这个任务在再下一次的事件循环中执行)。
    4. 同步任务执行完之后,首先检查微任务队列, 即 microtask队列,发现此队列不为空,执行第一个promise的then回调,输出 'promise1',然后执行第二个promise的then回调,输出'promise3',由于第一个promise的.then()的返回依然是promise,所以第二个.then()会放到microtask队列继续执行,输出 'promise2';
      5.此时microtask队列为空,进入下一个事件循环, 检查宏任务队列,发现有 setTimeout的回调函数,立即执行回调函数输出 'setTimeout---0',检查microtask 队列,队列为空,进入下一次事件循环.
    5. 检查宏任务队列,发现有 setTimeout的回调函数, 立即执行回调函数输出'setTimeout---200'
    6. 接着遇到setTimeout 0,它的作用是在 0ms 后将回调函数放到宏任务队列中,检查微任务队列,即 microtask 队列,发现此队列不为空,执行promise的then回调,输出'promise5'。
    7. 此时microtask队列为空,进入下一个事件循环,检查宏任务队列,发现有 setTimeout 的回调函数,立即执行回调函数输出,输出'inner-setTimeout---0'。代码执行结束。

    相关文章

      网友评论

          本文标题:event loop

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