js的同步与异步
众所周知,js是一个单线程的语言,学过java、c之类的都知道,其他语言有个叫类继承的东西,就相当于开辟另个一个流水线,是多线程
而javascript就像一条流水线,它无法开辟别的流水线,是一个单线程,也就是说js要么加工,要么包装,不能同时进行多个任务和流程
同步与异步
什么是同步,什么是异步
举个例子,我一边吃饭一边看剧,这是同步还是异步?有人说我同时在做2件事情,那肯定是异步了,但这其实是同步。
以js来说,同步就是在浏览器执行js代码的时候,将所有同步(也就是大部分的代码)的代码放到一个执行栈中当中,遇到异步代码就把异步代码放到任务队列中,这样就形成了异步操作,同步与异步的差别就在于这条流水线上各个流程的执行顺序不同
这也是js被称为单线程的原因,相比于其他的多线程语言而言,js对于同步代码与异步代码,只能选择其中一个执行,而其他语言可以同时进行
setTimeout和setInterval
在js中,最基础的异步就是setTimeout喝setInterval这两个函数,但是很少人知道这两个人其实是异步,简单介绍一下吧
两者都是定时器
functionvoid(){};setTimeout(void,1000);//隔1000毫秒后执行一次void,然后就不会在执行了setInterval(void,1000);//每隔1000毫秒(1秒)执行一次void
同步与异步的例子
用官方一点的话来讲,当一个js被执行的时候,把同步代码全放到一个执行栈里面,异步代码放到一个任务队列中,当栈执行完毕后开始执行任务队列
很多人不理解这一句话,这里分别来解释一下,首先:
- 执行栈:学过数据结构的应该都知道,栈的顺序是filo(first in last on),就是说栈里的代码是先进后出的
- 任务队列:这里用到的就是队列,队列的顺序是fifo(first in first on),队列里的代码是先进先出了解完这些词什么意思后,举个例子来细说一下:
<script>functionadd(){ console.log(2)}functionadd3(){ console.log(5)}functionadd2(){ console.log(4)} console.log(1)setTimeout(add,5000); console.log(3)setInterval(add2,1000)setTimeout(add3,1000)</script>
执行的结果是 首先,同步的代码是console.log(1)和log(3),所以先输出了1,3,然后就是异步的地方了。 异步三个代码,setTimeout、setInterval、setTimeout,当我们执行完同步代码(也就是输出1,3)开始执行异步代码对于第一个异步操作,因为我们设置的延迟时间为5秒(这个地方,虽然没有显示出来,但是这个异步操作已经开始执行,也就是说当代码执行到这一步的时候计时就已经开始),然后就是setInterval(add2,1000)也就是4,5,4,4,4,然后此时,设置的第一个延迟5秒到了,就输出一个2。 然后来解释下为什么说同步是栈,而异步是队列 我们同步的入栈顺序是log(1),log(3),然后出栈就是1,3,输出也就是1,3异步的入队顺序是,add,add2,add3,出来的时候也是add,add2,add3,但由于add的延迟原因,所以add2先输出 所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行
事件循环
当执行异步任务的时候,异步任务中可能也包含同样的同步任务与异步任务,顺序还是一样的,就算任务队列中没有任务也会去执行,这个过程会无限循环下去,这就是事件循环
宏任务与微任务
宏任务:普通任务,正常执行。正常的异步任务都是宏任务,最常见的就是定时器(setInterval, setImmediate, setTimeout)、IO任务
微任务:优先于宏任务执行(但不会抢断)。微任务出现比较晚,queueMicrotask、Promise和async属于微任务(当然,async就是promise)
我们可以看出来,微任务的优先级比宏任务高,一个任务结束后,事件循环会找到并执行全部微任务,然后再查找其他任务,那么,怎么分别宏任务和微任务呢?
分辨宏任务与微任务
来看个例子
<script>
console.log('aaa');setTimeout(()=> console.log(111),0);//异步任务queueMicrotask(()=> console.log(222));//异步任务
console.log('bbb');</script>
PS:setTimeout(() => console.log(111), 0);这里的()=>就类似于定义一个函数然后调用
输出的结果是
aaa
bbb
222
111
执行顺序就像我们之前说的,先执行同步的,也就是aaa,bbb,然后在执行异步的,但是这里,setTimeout
在queueMicrotask前面,却还是先执行了queueMicrotask,就是因为queueMicrotask是微任务,而setTimeout是宏任务,也就是说在异步中,会先完成所有的微任务,然后再去执行宏任务
为什么会有宏任务与微任务
每个代码的影响不一样,重要性也不一样,按照官方的设想就是,任务之间的不平等,有些任务对于用户而言更加重要,需要先执行,有些任务(类似定时器)晚点执行也没有什么问题
宏任务和微任务相当于一种优先级队列的方式
版权归原作者 谢谢,我还在努力 所有, 如有侵权,请联系我们删除。