浅谈JavaScript中的异步运行机制

本文深入探讨JavaScript的宏任务与微任务,解释它们的执行顺序以及与DOM渲染的关系。通过示例代码阐述EventLoop的工作原理,强调Promise在DOM渲染前执行,而setTimeout作为宏任务在渲染后执行。理解这一机制对于优化JavaScript代码和提升性能至关重要。
摘要由CSDN通过智能技术生成

问题描述

不知道大家在看面试题的时候,是不是会经常看到一写问你打印顺序的题。类似下面这种

setTimeout(() => {
    console.log('1')
}, 0)
console.log('2');
new Promise((resolve) => {
    console.log('3');
    resolve()
}).then(() => {
    console.log('4');
}).then(()=>{
    console.log('5')
})

相信这种题对大家来说都是信手拈来的了。但有的时候我就在想,为什么他就是这么执行的呢?很想去了解一下背后的执行机制。经过我的一番学习,今天就想和大家一起分享,探讨一下关于这方面的一下知识。写的不好或者有错漏的地方,也非常欢迎大家指正。
从这个题来看,相信大家也都知道打印的顺序,也知道 setTimeoutPromise 都是耗时任务,肯定不会顺着执行,那是 setTimout 先执行呢还是 Promise 先执行呢?也有很多人知道setTimout 是宏任务 Promise中的 then() 是微任务。说了这么多那是宏任务和微任务,为什么微任务比宏任务先执行?我们来一起探讨一下。

宏任务Macro Task 和 微任务Micro Task

宏任务和微任务只不过是 JavaScript 中异步任务的两个分类而已。我们要知道是宏任务和微任务两者有什么本质的区别。下次在看到这种问题,呸,以后他都不配称之为问题了。当然,只是开个玩笑,只能说在日常的工作中,可能对这些问题,处理起来更有信心和把握。
其实你会发现,常见的微任务 Promiseasync/await,常见的宏任务:setTimeoutsetInterval、onClick等 DOM 操作,有木有嗅到一丝丝不是一个级别的东西,setTimeout,setInterval 这些好像是浏览器规定的。而 Promiseasync/await 貌似就是 ES6+ 语法的一些规定。像这些微任务其实会存放在一个叫 Micro Task Queen 里面,而宏任务会放在 Web APIs 里面。而他们的执行,会先执行 Micro Task Queen 中的任务,然后再执行 Web APIs 里的任务。

我想到这里,我们就应该算是比较深的层面了解了为什么宏任务会比微任务慢执行了吧。

那宏任务和微任务是和 DOM 渲染的执行顺序是怎么样的呢?我们借助下面一段代码来感受一下吧:

var container = $('#container');
const $p1 = $('<p>HTML5</p>'),
      $p2 = $('<p>JavaScript</p>'),
      $p3 = $('<p>CSS3</p>');

container.append($p1)
         .append($p2)
         .append($p3)
const childsLength = $('#container').children().length;

Promise.resolve().then(() => {
    console.log('微任务': childsLength);
    alert('请注意看页面的DOM元素是否已经渲染')
})

setTimeout(() => {
    console.log('宏任务': childsLength);
    alert('请注意看页面的DOM元素是否已经渲染')
}, 0)

Event Loop 和 DOM 渲染

众所周知 javaScript 是单线程的,而且他和 DOM 渲染共用一个线程。JavaScript 在执行的时候,是需要留事件给浏览器进行 DOM 渲染的。那他是怎么实现这种调度的呢?我们可以尝试去理解一下他的思路:

  1. 执行同步代码,在遇到异步的回调函数时,会把异步的回调放到一个叫 CallBack Stack 的栈中
  2. 当全部的同步代码执行完以后,就是一个轮询了。一个轮询以后,线程会执行 CallBack Stack 中的回调函数。
  3. CallBack Stack 中的回调函数执行完成以后,会执行 Micro Task Queue 中的微任务
  4. 浏览器会尝试执行 DOM 渲染
  5. 执行 Web APIs 中的宏任务
  6. 最后再次触发 Event Loop

为什么说是尝试执行 DOM 渲染呢?因为 Callback 函数执行以后,不一定会有 DOM 的变化,也就不一定需要去执行 DOM 渲染。如果说,上面说的有点不好理解的话,也可以回看上面那段简单的代码来尝试体会一下这个过程。

小结

  • 宏任务是在 DOM 渲染之后 才会触发执行的,如 setTimeout,微任务是在 DOM 渲染之前 才会触发执行的,如 Promise
  • 常见的宏任务:setTimeoutsetIntervalAjaxDOM 事件
  • 常见的微任务:Promiseasync / await

当然,可能还有很多东西没有写到和说明白,欢迎各位大牛批评指正。若后面发现更多内容,也会进行改正和更新的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值