javaScript 进阶之路 --- 《 宏任务和微任务 》(一)

简介: javaScript 进阶之路 --- 《 宏任务和微任务 》

image.png

宏任务和微任务


前言: 上一篇我们知道了 “回调地狱” 是如何产生的。并且成功引入了 Promise 的核心知识。距离 《手写 Promise》 又更近了一步,但是我们仍需要去理解更深层次的概念----- 宏任务和微任务 ,才能继续往下讲解。

我非常希望你能在阅读完前置任务后再往下阅读本文(0/3)

我的每一篇博文的出发点都是:我是在面向一个初学者来进行讲解的,所以我在阐述某些知识点的时候,不会写一些很高深的话来凸显自己的水平,都会以:“假如我是一个初学者,当时如果有人这样告诉我的话该有多好~” 这也是费曼学习法的观点。Promise 在实际开发过程中是百分百最经常使用的,所以如果你是以找工作为目的的学习,我希望你能好好的理解这几篇文章内容,真心希望大家能在我的博文中领悟到一些东西。🎁

一. 做个 demo 热热身


别着急,我们先回顾一下。之前在讲 JS代码的运行机制时,我们大概知道setTimeout 会将自身参数,也就是传入的回调函数推进一个任务队列,然后等待主线程执行完毕后再将任务队列中的代码推进主线程去执行。并且会无限循环这个过程,这个过程被我们称为 “事件循环(eventloop)”

下面的代码,我相信你已经知道原因了。

image.png

5d71d7fed9a74d36aa5b0810f648ddbd_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

ok,我们现在看下一段代码。思考一下,你觉得会是?

image.png

结果如下:

image.png

如果你没感觉到差异,小伙子水平不错哦~ 👏

不理解别着急,我来解释一下原因是什么。首先 setTimout('1') 的输出肯定被放进了 任务队列 ,所以 console.log('3') 的输出结果 3 是肯定要在 1 之前,这个我相信你肯定知道原因。关键就在于为什么在 Promise 这里的 2 会在第一输出。

下面我不写箭头函数了,我害怕箭头函数会让初学者看不出来这就是一个函数而已。

image.png

没错,它真的就是一个普普通通的函数。如果你对 Class 熟悉的话,它其实就是下面的写法。

image.png

我再强调一遍,这个 “executor” 构造器函数就是一个普普通通的函数仅此而已,不是什么关键词!!!就是一个函数。当这个函数作为 Promise 类的参数时,会被在 Promise 类的 constructor 函数中马上被调用。

所以我们可以得出,传递给 Promise类 的回调函数,会被马上执行。它被并没有被推进任务队列中去。

image.png

又因为它是在 console.log(3) 之前写的,根据我们 JS 代码从上往下执行的原理,自然而然的结果就是 2->3->1

image.png

是不是觉得很简单呢?我们稍微加一点难度,看下面一段代码。

image.png

别直接想结果,你想一想控制台会是什么样子的?

image.png

奇怪?我们的 2 跑哪里了?如果你不知道这一点,我希望你回过头去看一下上一篇- 手写“回调地狱”,再来继续下面的学习。

从上一章节我们其实我们知道,我们如果要取 Promise,resolve 保存的数据,需要在 Promise 实例身上的 then 方法中去拿,由此可知我们需要按照下面的写法才能拿到数字 2

image.png

那么问题来了,接下来的输出顺序会是?我们打印一下:

6107dac0d4654e25b851b6c1c59975e2_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

  1. 怎么回事呢?怎么顺序就又变了呢?🤔

二. 宏任务和微任务(MacroTask & MicroTask)


setTimout 的回调函数是会被放在任务队列的对吧?我们都知道任务队列里的任务会乖乖排队,等着主线程老大执行完再进去主线程去执行。关键点就来了!这里有个插队的!!没错,就是我们的微任务队列

是的,在 JS 里其实存在另外一个任务队列---微任务队列(MicroTask)。我们的 setTimout 的回调函数其实被放进了一个叫宏任务队列里。为什么会产生两个队列呢?其实很好理解。

我们假设一个场景。我们去饭店吃饭。我们总是会把菜点完,然后把写着好几个菜的菜单拿给服务员,最好服务员一起送过去厨房做对吧?这时候有意思的点就来了,厨师👨‍🍳拿到菜单以后,一看《土豆炖牛肉》,《红烧肉》,《鸡蛋汤》。我感觉如果是一个正常的厨师师傅,都会给做菜顺序安排合理。“我不可能一看,第一行《土地炖牛肉》,后面的我压根不看,我就必须把这个菜先做了才能做后面的。”结果第一道菜50多分钟,客人干等着50分钟。

这时候就把《土地炖牛肉》开启高压锅放进了宏任务队列,转手把《鸡蛋汤》和《红烧肉》放进主线程去做。

当《土豆炖牛肉》快好的前几分钟,(注意!:这时候红烧肉和鸡蛋汤已经吃饱喝足被消灭了) 你突然又点了一个《拍黄瓜》🥜。师傅一看,《拍黄瓜》简单啊,虽然这个菜是最后上的,但是师傅直接给你放《微任务》啪啪啪几分钟给你搞好了,速度肯定比《土豆炖牛肉》剩下几分钟还要快,自然而然你就先吃到了《拍黄瓜》。

同理,在 JS 中,我们去拿一些页面相对更重要数据的时候,就是需要去“插“一些相对不那么“重要”的宏任务的队,才能保证我们页面的正确加载。而很显然,我们的 Promise 就是需要存放相对重要的数据时用得,所以它需要比 setTimeout 这个宏任务队列在事件循环的时候先执行。所以事件循环会是下面的顺序。

image.png

如果没有的话,再去询问宏任务队列

image.png

了解了这些以后,我们再回过头看一下之前的代码,就很清晰了。

image.png

首先控制台先执行同步任务 console.log('3'),之后主线程为空。然后紧接着就去询问微任务队列console.log('2'),微任务队列执行完毕,最后询问宏任务队列。 console.log('1')

结果输出结果就如下所示:

image.png

相关文章
|
3月前
|
JavaScript 前端开发 API
详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务
该文章详细讲解了队列数据结构在前端开发中的应用,并深入探讨了JavaScript的事件循环机制,区分了宏任务和微任务的执行顺序及其对前端性能的影响。
|
2月前
|
JavaScript 前端开发 调度
在JavaScript中异步任务里的微任务和宏任务的特点和生命周期
在JavaScript中异步任务里的微任务和宏任务的特点和生命周期
45 0
|
3月前
|
前端开发 JavaScript API
JavaScript 的宏任务和微任务有什么区别
【9月更文挑战第6天】JavaScript 的宏任务和微任务有什么区别
88 4
|
4月前
|
存储 前端开发 JavaScript
JavaScript 并发任务控制
【8月更文挑战第31天】JavaScript 并发任务控制
52 2
|
4月前
|
运维 JavaScript 安全
自动化运维:使用Ansible简化日常任务深入理解Node.js事件循环和异步编程
【8月更文挑战第27天】在快节奏的技术环境中,自动化不再是奢侈品,而是必需品。本文将引导你通过Ansible实现自动化运维,从基础到高级应用,解锁高效管理服务器群的秘诀,让你的IT操作更加流畅和高效。
|
5月前
|
前端开发 JavaScript 安全
JavaScript进阶-JavaScript库与框架简介
【7月更文挑战第11天】JavaScript库和框架加速Web开发,但也带来挑战。选择适合项目、团队技能的库或框架,如React、Angular、Vue,是关键。保持依赖更新,注意性能优化,避免过度依赖。遵循最佳实践,确保安全性,如防XSS和CSRF。学习基础,结合代码示例(如React计数器组件),提升开发效率和应用质量。
64 1
|
5月前
|
资源调度 JavaScript 前端开发
JavaScript进阶 - JavaScript库与框架简介
【7月更文挑战第5天】JavaScript库和框架构成了前端开发的核心,如jQuery简化DOM操作,Angular、React和Vue提供全面解决方案。选择时要明确需求,避免过度工程化和陡峭学习曲线。使用版本管理工具确保兼容性,持续学习以适应技术变化。示例展示了jQuery和React的简单应用。正确选择和使用这些工具,能提升开发效率并创造优秀Web应用。
52 2
|
5月前
|
JavaScript IDE 持续交付
阿里云云效产品使用合集之如何配置 Node.js构建任务让其在Windows环境中进行
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
5月前
|
缓存 前端开发 JavaScript
JavaScript进阶 - Web Workers与Service Worker
【7月更文挑战第10天】在Web开发中,Web Workers和Service Worker提升性能。Workers运行后台任务,防止界面冻结。Web Workers处理计算密集型任务,Service Worker则缓存资源实现离线支持。常见问题包括通信故障、资源限制、注册错误及缓存更新。通过示例代码展示了两者用法,并强调生命周期管理和错误处理的重要性。善用这些技术,可构建高性能的Web应用。
107 0
|
5月前
|
XML 前端开发 JavaScript
JavaScript进阶 - AJAX请求与Fetch API
【7月更文挑战第9天】JavaScript进阶:AJAX与Fetch API对比。AJAX用于异步数据交换,XMLHttpRequest API复杂,依赖回调。Fetch API是现代、基于Promise的解决方案,简化请求处理。示例:`fetch('url').then(r => r.json()).then(data => console.log(data)).catch(err => console.error(err))`。注意点包括检查HTTP状态、错误处理、CORS、Cookie和超时。Fetch提高了异步代码的可读性,但需留意潜在问题。
105 0