分享

js中的同步和异步,宏任务和微任务,async和await

 印度阿三17 2020-02-28

所有的任务分为两种,一种是同步任务,一种是异步任务。

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。这里说到了一个“队列”(即任务队列),该队列放的是什么呢,放的就是setTimeout中的function,这些function依次加入该队列,即该队列中所有function中的程序将会在该队列以外的所有代码执行完毕之后再以此执行,这是为什么呢?因为在执行程序的时候,浏览器会默认setTimeout以及ajax请求这一类的方法都是耗时程序(尽管可能不耗时),将其加入一个队列中,该队列是一个存储耗时程序的队列,在所有不耗时程序执行过后,再来依次执行该队列中的程序。具体来说,异步运行机制如下:

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。

setTimeOut函数为异步任务,for循环为同步任务,setTimeOut里的函数为回调函数。执行顺序为:同步优先,异步靠边,回调垫底。所以即使setTimeOut的时间参数是0依然会放到任务队列里,而不是主线程。主线程执行完for循环以后才执行异步任务setTimeOut。另外setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。于是就有一个概念——任务队列。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。于是JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

 

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成这门语言的核心特征,将来也不会改变。

注:所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。

总结:计算机中的同步就是排队等待,假如你是第一百零一个备胎,那你只能等前面的一百个爆了之后才能‘处理'你。异步就是,尽管你是第一百零一个,她还是能照顾到你的感受。

  • js是同步的?是的,单线程,那肯定只能同步(排队)执行咯
  • js为什么需要异步?如果JS中不存在异步,只能自上而下执行,万一上一行解析时间很长,那么下面的代码就会被阻塞。对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验

 例:

也就是说,setTimeout里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。

总结:同步可以保证顺序一致,但是容易导致阻塞;异步可以解决阻塞问题,但是会改变顺序性,根据不同的需要去写你的代码。

Promise是异步的,是指他的then()和catch()方法,Promise本身还是同步的,所以这里先执行a变量内部的Promise同步代码。(同步优先)

注意 new Promise() 是同步方法,resolve才是异步方法。 

同步(Promise)>异步(微任务(process.nextTick ,Promises.then, Promise.catch ,resove,reject,MutationObserver)>宏认为(setTimeout,setInterval,setImmediate))

process.nextTick> Promises.then

同步代码执行完成后,才会再去执行异步,哪怕异步已经到了执行的时间了。

JavaScript的任务分为微任务(Microtasks)和宏任务(task);

  • 宏任务是主流,当js开始被执行的时候,就是开启一个宏任务,在宏任务中执行一条一条的指令;
  • 宏任务可以同时有多个,但会按顺序一个一个执行;
  • 每一个宏任务,后面都可以跟一个微任务队列,如果微任务队列中有指令或方法,那么就会执行;如果没有,则开始执行下一个宏任务,直到所有的宏任务执行完为止,微任务相当于宏任务的小尾巴;
  • 为什么有了宏任务,还会有微任务存在?因为宏任务太占用性能,当需要一些较早就准备好的方法,排在最后才执行的时候,又不想新增一个宏任务,那么就可以把这些方法,一个一个的放在微任务队列里面,在这个宏任务中的代码执行完后,就会执行微任务队列。

 [宏任务:macro task]

        - 定时器

        - 事件绑定

        - ajax

        - 回调函数

        - Node中fs可以进行异步的I/O操作

[微任务:micro task]

        - Promise(async/await)  => Promise并不是完全的同步,当在Excutor中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会再去调用resolve/reject把存放的方法执行

        - process.nextTick (node中实现的api,把当前任务放到主栈最后执行,当主栈执行完,先执行nextTick,再到等待队列中找)

   - MutationObserver   (创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。)

任务队列到达时间后先进先出的原则

 

参考:

1:https://blog.csdn.net/qq_40959677/article/details/95961443

2:https://www.baidu.com/link?url=SBAnO_y-vTjtcvs-NQlfPeEKW1NTRrXP1yiYhf-nLeBvf88WbIi01LvhphfWFKRrR1ay8KFy0rWDuAM1B4M5An-n3nbVVXSmnB0MD2Td7TK&wd=&eqid=b29f3105000520ac000000065e54ed37

 

~李疆 发布了323 篇原创文章 · 获赞 128 · 访问量 13万 私信 关注 来源:http://www./content-4-643401.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多