美文网首页
JS事件循环EventLoop初探

JS事件循环EventLoop初探

作者: DarK_AleX_PSX | 来源:发表于2018-01-29 23:02 被阅读0次

    概念

    js是基于单线程运行的,而一些特定事件又是异步执行的,所以这种单线程+异步的执行方式一定是事件驱动的 而一般浏览器环境下有这样几种线程。

    js引擎线程 (解释执行js代码、用户输入、网络请求)主线程

    GUI线程 (绘制用户界面、与js主线程是互斥的)先绘制dom再绘制css

    http网络请求线程 (处理用户的get、post等请求,等返回结果后将回调函数推入任务队列)

    定时触发器线程 (setTimeout、setInterval等待时间结束后把执行函数推入任务队列中)

    浏览器事件处理线程(将click、mouse等交互事件发生后将这些事件放入事件队列中)

    上一张经典的eventLoop图,了解几个基本概念

    [图片上传失败...(image-a3d100-1517238113235)]
    1,栈(stack):队列优先,由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    2.堆(heap):先进后出;动态分配的空间
    JavaScript中的变量分为基本类型和引用类型。基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象
    这里引入一个概念(图上没有),就是js中的task和microTask 一般来讲,我们把setTimeout,setInterval,浏览器的dom操作,用户点击等交互事件归结为task,而Promise callback Mutation callback还有nextTick我们归结为microTask,

    那问题就来了,js中task和microTask执行顺序是怎样的

    由于js是单线程,所有的多线程任务最后都要压入主线程执行栈去执行,如图所示,task会放入回调队列里 由eventLoop取出依次执行。

    这里可以解释一个小问题,如果多个setTimeout的情况下,执行时间不是特别的精确,setTimeout 它会在延迟时间结束后分配一个新的 task 至 event loop 中,而不是立即执行,所以 setTimeout 的回调函数会等待前面的 task 都执行结束后再运行。

    说到这里好像还没有microTask什么事,那microTask在什么时候执行呢,通俗的说,你可以将microTask理解为一个爱插队的大妈,就是在一个task事件结束后,microTask就插入执行栈立即执行,执行顺序是主线程执行栈的队尾插入,callback quene之前

    上一段代码吧,来直观的了解一下执行顺序

     console.log('start');
      
     setTimeout(function() {
        console.log('setTimeout1');
            setTimeout(function() {
               console.log('setTimeout2');
           },0);
        console.log('setTimeout3');
      }, 0);
      
      Promise.resolve().then(function() {
        console.log('promise1');
      }).then(function() {
       console.log('promise2');
     });
     
     console.log('end');
    

    最后结果是 1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2

    顺序是,先执行打印start 然后打印edn 这时候microTask (promise)插队进入 打印promise1,promise2, 然后执行setTimeout打印setTimeout1,setTimeout3,这里可以看做
    console.log('setTimeout1');
    console.log('setTimeout3');
    这两句一起压入执行栈,

    setTimeout(function() {
            console.log('setTimeout2');
    },0);
    

    进入task队列,由EventLoop取出,所以最后执行顺序是
    1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2

    相关文章

      网友评论

          本文标题:JS事件循环EventLoop初探

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