最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 浏览器中的事件循环机制(EventLoop)

    正文概述 掘金(小桂代码)   2021-04-04   604

    前言

    • Event Loop即事件循环 是指浏览器或Node的一种解决js单线程运行时不会阻塞的一种机制 也就是我们经常使用异步的原理 为了实现js的异步概念
    • 进程: 计算机分配任务的最小单位
    • 线程: 进程里包含多个线程
    • EventLoop解决的是 js执行时可能会调用异步方法 这些方法是怎样调度执行的

    浏览器的进程

    • 每一个tab页都是进程 (tab页互不影响)
    • 浏览器也有一个主进程 (用户界面)
    • 网络进程 (处理请求)
    • GPU进程 3d 绘制
    • 第三方插件的进程
    • 渲染进程 每个tab页里 都有一个渲染进程 (浏览器内核)

    渲染进程

    • 包含着多个线程
    • GUI渲染线程 用来渲染页面
    • JS引擎线程 他和页面渲染时互斥
    • 事件触发线程 独立的线程 EventLoop
    • 事件 click setTimeout ajax也是一个独立线程

    流程

    • 如下图示
    • 宏任务 如: setTimeout setInterval postMessage MessageChannel setImmediate...
    • 微任务 如: promise.then mutationObserver
    * js执行的时候 会从上到下执行
    * 遇到函数会创建执行上下文 放入到执行栈中
    * 执行完毕后会出栈 执行时可能会发生异步事件(内部会调用浏览器Api 如: `setTimeout`, `ajax`...)
    
    * 当我们执行上下文栈都执行完毕后 等会可能api(如 `setTimeout`)执行完成或者时间到达
    * 会被维护到一个事件队列中 (原则先进先出) 
    
    * 不停的扫描队列 将队列里的任务拿出来放到上下文栈中执行 
    * 事件循环线程是专门干这件事的 检测当前执行栈是否为空 如果为空 从事件队列中取出**一个来执行** (如`setTimeout(宏任务)`)
    
    * 当代码执行时还会有一些任务 以`promise.then(微任务)`为例
    * 每次执行宏任务的时候 都会单独创建一个 微任务队列 (原则先进先出)
    
    * 微任务在执行完毕后 浏览器会检测是否要重新渲染 浏览器有刷新频率 大约16.6ms
    * 小于这个时间 浏览器是不会渲染的
    
    * 每次循环一次都会执行一个宏任务 并清空对应的微任务队列 
    * 微任务中在执行时再生成微任务 会在本轮直接清空
    * 每次循环完毕后 都要看是否要渲染 如果需要渲染才渲染
    
    
    浏览器中的事件循环机制(EventLoop)

    示例

    微任务和GUI渲染

    // 页面的背景色 有没有从红到黄
    // 执行栈       [console.log(1) console.log(3)]
    // 微任务队列    [Promise.then]
    // 执行完宏任务 清空微任务
    // 再去渲染 页面没有从红到黄, 直接就是黄色
    
    // log: 1 3 2
    document.body.style.background = 'red';
    
    console.log(1)
    Promise.resolve().then(()=>{
        console.log(2)
        document.body.style.background = 'yellow';
    })
    console.log(3);
    
    

    事件任务

    <button id="button">事件按钮</button>
    
    // 第一种
    // 当前未点击button按钮 直接在下 button.click() 输出的结果是什么
    // 当前两个事件在执行栈中执行
    // 执行栈       ['click1'  'click2']
    // 微任务队列    [Promise.then1  Promise.then2]
    
    // log: 'click1'  'click2' 'c1-micro-task1' 'c2-micro-task2'
    button.addEventListener('click',()=>{ // 1
        console.log('click1');
        Promise.resolve().then(()=>console.log('c1-micro-task1'))
    })
    button.addEventListener('click',()=>{ // 2
        console.log('click2');
        Promise.resolve().then(()=>console.log('c2-micro-task2'))
    })
    button.click();
    
    // 第二种
    // 当前点击button按钮 输出的结果是什么
    // 上面流程我们说道
    // 事件循环线程是专门干这件事的 检测当前执行栈是否为空 如果为空 从事件队列中取出**一个来执行**
    // 一个一个拿到执行栈执行
    // 宏任务队列 [addEventListener1  addEventListener2]
    
    // 先拿出 addEventListener1, 并清空微任务队列 [Promise.then1]
    // 再拿出 addEventListener2, 并清空微任务队列 [Promise.then2]
    
    // log: 'click1' 'c1-micro-task1'  'click2'  'c2-micro-task2'
    button.addEventListener('click',()=>{ // 1
        console.log('click1');
        Promise.resolve().then(()=>console.log('c1-micro-task1'))
    })
    button.addEventListener('click',()=>{ // 2
        console.log('click2');
        Promise.resolve().then(()=>console.log('c2-micro-task2'))
    })
    

    定时器任务

    // 执行栈执行 有定时器 时间以到 放到 宏任务队列 [setTimeout2]
    // 执行栈执行完
    // 接着清空微任务队列[Promise.then1]
    
    // 微任务有定时器 时间以到 放到 宏任务队列 [setTimeout2 setTimeout1]
    
    // 最后一个一个宏任务 执行
    
    // log: Promise1 setTimeout2 Promise2 setTimeout1
    Promise.resolve().then(() => { // 1
        console.log('Promise1')
        setTimeout(() => {
            console.log('setTimeout1')
        }, 0);
    })
    
    setTimeout(() => { // 2
        console.log('setTimeout2');
        Promise.resolve().then(() => {
            console.log('Promise2')
        })
    }, 0);
    

    一道有意思的面试题

    • await 会暂停async 函数内后面的代码
    • 先执行 async 函数外的同步代码
    • 如果 await 的是 Promise 对象
    • 等着 Promise 对象 的状态是status = 'FULFILLED'
    • 然后把 resolve 的参数作为 await 表达式的运算结果返回后
    • 再继续执行 async 函数内后面的代码
    // log: 1 6 2 3 8 7 4 5
    
    console.log(1);
    
    async function async () {
        console.log(2);
        await console.log(3);
        console.log(4)
    }
    
    setTimeout(() => {
    	console.log(5);
    }, 0);
    
    const promise = new Promise((resolve, reject) => {
        console.log(6);
        resolve(7)
    })
    
    promise.then(res => {
    	console.log(res)
    })
    
    async (); 
    
    console.log(8);
    


    起源地下载网 » 浏览器中的事件循环机制(EventLoop)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元