1

js是单线程语言,即同一时间只能做一件事,必须执行完当前代码才能往下走,某些比较耗时的任务卡着,后面的任务要一直等,导致IO操作(输入/输出,耗时但cpu闲置)时造成性能浪费的问题。
异步可以解决IO操作带来的性能浪费,即与同步相反,不按顺序执行,可以让后面的任务先执行。
那同步和异步任务的执行顺序是什么呢?

所有的任务都在主线程执行,js的单线程任务被分为同步任务、异步任务:

  1. 同步任务:直接会进入主线程执行,形成一个执行栈(栈:后进先出,从栈顶一端进/出)
  2. 异步任务:在“任务队列”中执行(队列:先进先出,排在前面的优先被执行,从尾部进头部出,但要注意定时器任务是否到了时间)
  3. 执行栈中的全部同步任务执行完毕(调用栈被清空),就会通过回调函数的方式去调用“任务队列”的异步任务,异步任务这时进入主线程执行。(异步任务必须指定回调函数,主线程去执行异步任务,就是去执行其对应的回调函数)
  4. 主线程不断重复上面的第 3 步,只要主线程没有可执行的任务,则就会读取“任务队列”(EventLoop)

在JavaScript中,异步任务又被分为两种:宏任务(MacroTask)也叫Task、微任务(MicroTask):

  1. 宏任务:script全部代码、setTimeout(基本是最后执行)、setInterval、setImmediate、I/O、UI Rendering
  2. 微任务:mutation observe的回调、promise的回调
    (在Promise中的代码是同步任务,执行resolve或者reject回调的时候,此时是异步操作,会先将then/catch等放到异步任务中的微任务队列)

执行顺序:
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务(microTask)队列是否为空,如果为空的话,就执行Task(宏任务),否则就一次性执行完所有微任务。
每次单个宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。

即:
同步任务 > event loop去检测微任务(一次性执行完所有) > 宏任务(执行一个) > event loop去检测微任务(一次性执行完所有)...

参考:

  1. https://www.ruanyifeng.com/blog/2014/10/event-loop.html
  2. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Event...
  3. https://segmentfault.com/a/1190000014940904
  4. https://juejin.cn/post/6844903764202094606?utm_source=gold_br...
  5. https://segmentfault.com/a/1190000015317434

此时此刻的云
10 声望0 粉丝