循环机制(event loop)之宏任务和微任务

一、前言

js任务分为同步任务异步任务异步任务又分为宏任务和微任务,其中异步任务属于耗时的任务。

二、宏任务和微任务有哪些?

宏任务:整体代码scriptsetTimeoutsetIntervalsetImmediate(Node.js)i/o操作(输入输出,比如读取文件操作、网络请求)ui render(dom渲染,即更改代码重新渲染dom的过程)异步ajax

微任务:Promise(then、catch、finally)async/awaitprocess.nextTick(Node.js)Object.observe (⽤来实时监测js中对象的变化,已废弃 )、 MutationObserver(监听DOM树的变化)

setTimeout

大名鼎鼎的setTimeout无需再多言,大家对他的第一印象就是异步可以延时执行,我们经常这么实现延时3秒执行:

复制代码
setTimeout(() => {
    console.log('延时3秒');
},3000)

我们还经常遇到setTimeout(fn,0)这样的代码,0秒后执行又是什么意思呢?是不是可以立即执行呢? 答案是不会的,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。举例说明:

复制代码
//代码1
console.log('先执行这里');
setTimeout(() => {
    console.log('执行啦')
},0);

//代码2
console.log('先执行这里');
setTimeout(() => {
    console.log('执行啦')
},3000);

代码1的输出结果是:

复制代码
先执行这里
执行啦

代码2的输出结果是:

复制代码
//先执行这里
// ... 3s later
// 执行啦

关于setTimeout要补充的是,即便主线程为空,0毫秒实际上也是达不到的。根据HTML的标准,最低是4毫秒。有兴趣的同学可以自行了解。

Promise与process.nextTick(callback)
  • Promise的定义和功能本文不再赘述,可以学习一下 阮一峰老师的Promise
  • 而process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数。

看例子:

复制代码
setTimeout(()=>{
  console.log('setTimeout1')
},0)
let p = new Promise((resolve,reject)=>{
  console.log('Promise1')
  resolve()
})
p.then(()=>{
  console.log('Promise2')    
})

最后输出结果是Promise1,Promise2,setTimeout1

Promise参数中的Promise1是同步执行的 其次是因为Promise是microtasks,会在同步任务执行完后会去清空microtasks queues, 最后清空完微任务再去宏任务队列取值。

复制代码
Promise.resolve().then(()=>{
  console.log('Promise1')  
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
})

setTimeout(()=>{
  console.log('setTimeout1')
  Promise.resolve().then(()=>{
    console.log('Promise2')    
  })
},0)

这回是嵌套,大家可以看看,最后输出结果是Promise1,setTimeout1,Promise2,setTimeout2

  • 一开始执行栈的同步任务执行完毕,会去 microtasks queues 找 清空 microtasks queues ,输出Promise1,同时会生成一个异步任务 setTimeout1
  • 去宏任务队列查看此时队列是 setTimeout1 在 setTimeout2 之前,因为setTimeout1执行栈一开始的时候就开始异步执行,所以输出 setTimeout1
  • 在执行setTimeout1时会生成Promise2的一个 microtasks ,放入 microtasks queues 中,接着又是一个循环,去清空 microtasks queues ,输出 Promise2
  • 清空完 microtasks queues ,就又会去宏任务队列取一个,这回取的是 setTimeout2
三、执行顺序

js代码在执行的时候,会先执行同步代码遇到异步宏任务则将异步宏任务放入宏任务队列中遇到异步微任务则将异步微任务放入微任务队列中 ,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后,再将异步宏任务从队列中调入主线程执行,一直循环至所有的任务执行完毕(完成一次事件循环EventLoop)。

题目练习:

练习一

复制代码
setTimeout(function () {
 console.log('1');
})
new Promise(function (resolve) {
 console.log('2');
 resolve();
}).then(function () {
 console.log('3');
})
console.log('4');
//打印顺序 2 4 3 1

练习二

复制代码
console.log(1);
setTimeout(function () {
  console.log(2);
  let promise = new Promise(function (resolve, reject) {
    console.log(3);
    resolve();
  }).then(function () {
    console.log(4);
  });
}, 1000);
setTimeout(function () {
  console.log(5);
  let promise = new Promise(function (resolve, reject) {
    console.log(6);
    resolve();
  }).then(function () {
    console.log(7);
  });
}, 0);
let promise = new Promise(function (resolve, reject) {
  console.log(8);
  resolve()
}).then(function () {
  console.log(9);
}).then(function () {
  console.log(10)
});
console.log(11);
//执行顺序:1 8 11 9 10 5 6 7 2 3 4
相关推荐
●VON20 分钟前
React Native for OpenHarmony:项目目录结构与跨平台构建流程详解
javascript·学习·react native·react.js·架构·跨平台·von
爱吃大芒果37 分钟前
Flutter for OpenHarmony 实战:mango_shop 路由系统的配置与页面跳转逻辑
开发语言·javascript·flutter
qq_1777673741 分钟前
React Native鸿蒙跨平台实现消息列表用于存储所有消息数据,筛选状态用于控制消息筛选结果
javascript·react native·react.js·ecmascript·harmonyos
沐雪架构师1 小时前
LangChain 1.0 Agent开发实战指南
开发语言·javascript·langchain
2501_940007891 小时前
Flutter for OpenHarmony三国杀攻略App实战 - 战绩记录功能实现
开发语言·javascript·flutter
摘星编程1 小时前
React Native + OpenHarmony:自定义useEllipsis省略号处理
javascript·react native·react.js
这是个栗子2 小时前
【Vue代码分析】前端动态路由传参与可选参数标记:实现“添加/查看”模式的灵活路由配置
前端·javascript·vue.js
刘一说2 小时前
Vue 动态路由参数丢失问题详解:为什么 `:id` 拿不到值?
前端·javascript·vue.js
方也_arkling2 小时前
elementPlus按需导入配置
前端·javascript·vue.js
爱吃大芒果2 小时前
Flutter for OpenHarmony 实战: mango_shop 资源文件管理与鸿蒙适配
javascript·flutter·harmonyos