js是单线程语言,即同一时间只能做一件事,必须执行完当前代码才能往下走,某些比较耗时的任务卡着,后面的任务要一直等,导致IO操作(输入/输出,耗时但cpu闲置)时造成性能浪费的问题。
异步可以解决IO操作带来的性能浪费,即与同步相反,不按顺序执行,可以让后面的任务先执行。
那同步和异步任务的执行顺序是什么呢?
所有的任务都在主线程执行,js的单线程任务被分为同步任务、异步任务:
- 同步任务:直接会进入主线程执行,形成一个执行栈(栈:后进先出,从栈顶一端进/出)
- 异步任务:在“任务队列”中执行(队列:先进先出,排在前面的优先被执行,从尾部进头部出,但要注意定时器任务是否到了时间)
- 执行栈中的全部同步任务执行完毕(调用栈被清空),就会通过回调函数的方式去调用“任务队列”的异步任务,异步任务这时进入主线程执行。(异步任务必须指定回调函数,主线程去执行异步任务,就是去执行其对应的回调函数)
- 主线程不断重复上面的第 3 步,只要主线程没有可执行的任务,则就会读取“任务队列”(EventLoop)
在JavaScript中,异步任务又被分为两种:宏任务(MacroTask)也叫Task、微任务(MicroTask):
- 宏任务:script全部代码、setTimeout(基本是最后执行)、setInterval、setImmediate、I/O、UI Rendering
- 微任务:mutation observe的回调、promise的回调
(在Promise中的代码是同步任务,执行resolve或者reject回调的时候,此时是异步操作,会先将then/catch等放到异步任务中的微任务队列)
执行顺序:
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务(microTask)队列是否为空,如果为空的话,就执行Task(宏任务),否则就一次性执行完所有微任务。
每次单个宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。
即:
同步任务 > event loop去检测微任务(一次性执行完所有) > 宏任务(执行一个) > event loop去检测微任务(一次性执行完所有)...
参考:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。