zoukankan      html  css  js  c++  java
  • javascript event loop

    原文: https://blog.csdn.net/sjn0503/article/details/76087631

    简单来讲,整体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环至结束

    -----------------------------------------------------------------------

    我们知道 DOM 操作会触发浏览器对文档进行渲染,如修改排版规则,修改背景颜色等等,那么这类操作是如何在浏览器当中奏效的?至此我们已经知道了事件循环是如何执行的,事件循环器会不停的检查事件队列,如果不为空,则取出队首压入执行栈执行。当一个任务执行完毕之后,事件循环器又会继续不停的检查事件队列,不过在这间,浏览器会对页面进行渲染。这就保证了用户在浏览页面的时候不会出现页面阻塞的情况,这也使 JS 动画成为可能, jQuery 动画在底层均是使用 setTimeout 和 setInterval 来进行实现。想象一下如果我们同步的执行动画,那么我们不会看见任何渐变的效果,浏览器会在任务执行结束之后渲染窗口。反之我们使用异步的方法,浏览器会在每一个任务执行结束之后渲染窗口,这样我们就能看见动画的渐变效果了

    Several runtimes communicating together

    A web worker or a cross-origin iframe has its own stack, heap, and message queue. Two distinct runtimes can only communicate through sending messages via the postMessagemethod. This method adds a message to the other runtime if the latter listens to messageevents.

     --------------------------------------------------------------------分割线--------------------------------------------------------------------------------

    放个面试题,抛个砖:

    console.log('start')
    
    const interval = setInterval(() => {  
      console.log('setInterval')
    }, 0)
    
    setTimeout(() => {  
      console.log('setTimeout 1')
      Promise.resolve()
          .then(() => {
            console.log('promise 3')
          })
          .then(() => {
            console.log('promise 4')
          })
          .then(() => {
            setTimeout(() => {
              console.log('setTimeout 2')
              Promise.resolve()
                  .then(() => {
                    console.log('promise 5')
                  })
                  .then(() => {
                    console.log('promise 6')
                  })
                  .then(() => {
                    clearInterval(interval)
                  })
            }, 0)
          })
    }, 0)
    
    Promise.resolve()
        .then(() => {  
            console.log('promise 1')
        })
        .then(() => {
            console.log('promise 2')
        })
    

    不着急揭晓答案,先分析

    首先知晓:

    js是单线程语言

    也就是说一次就只能做一件事情。

    多数的网站不需要大量计算,程序花费的时间主要集中在磁盘 I/O 和网络 I/O 上面

    虽然SSD读取很快,但和CPU处理指令的速度比起来也不在一个数量级上,而且网络上一个数据包来回的时间更慢(注意过游戏的延迟吗)

    so: 一些cpu直接执行的任务就成了优先执行主线任务,然后需要io返回数据的任务就成了等待被执行的任务

    所以才会有同步任务(synchronous)和异步任务(asynchronous)之分

    同步任务:

    在主线程上排队执行的任务,前一个任务执行完毕,才能执行后一个任务;

    异步任务:

    不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

    总之:

    只要主线程空了,就会去读取”任务队列”,这就是JavaScript的运行机制

    Microtasks Macrotasks

    任务队列不止一个,还有 microtasks 和 macrotasks

    microtasks:

    • process.nextTick
    • promise
    • Object.observe
    • MutationObserver

    macrotasks:

    • setTimeout
    • setInterval
    • setImmediate
    • I/O
    • UI渲染

    whatwg规范:https://html.spec.whatwg.org/multipage/webappapis.html#task-queue

    • 一个事件循环(event loop)会有一个或多个任务队列(task queue)
    • task queue 就是 macrotask queue
    • 每一个 event loop 都有一个 microtask queue
    • task queue == macrotask queue != microtask queue
    • 一个任务 task 可以放入 macrotask queue 也可以放入 microtask queue 中

    理解了这些定义之后,再看执行原理:

    事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次从macro-task开始,找到其中一个任务队列执行完毕,然后再执行所有的micro-task,这样一直循环下去。

    还要注意一点:

    包裹在一个 script 标签中的js代码也是一个 task 确切说是 macrotask。

    所以文首面试题的答案为:

    start 
    promise 1 
    promise 2 
    setInterval 
    setTimeout 1 
    promise 3 
    promise 4 
    setInterval 
    setTimeout 2 
    promise 5 
    promise 6

    简单来讲,整体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环至结束

  • 相关阅读:
    PHP中的类函数和类对象
    PHP魔术方法__clone()篇
    PHP魔术方法__tostring()篇
    PHP魔术方法__call()篇
    自己写的PHP的mql类
    PHP的分页
    ThinkPHP的调用css,js和图片的路径
    JavaScript作用域链
    在Eclipse中开发WEB项目
    eclipse官方网址、各个版本的下载
  • 原文地址:https://www.cnblogs.com/oxspirt/p/9098616.html
Copyright © 2011-2022 走看看