循环机制(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
相关推荐
罗_三金7 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Fan_web44 分钟前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
好名字08212 小时前
monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)
前端·javascript
c#上位机2 小时前
C#事件的用法
java·javascript·c#
万物得其道者成2 小时前
React Zustand状态管理库的使用
开发语言·javascript·ecmascript
小白小白从不日白2 小时前
react hooks--useReducer
前端·javascript·react.js
下雪天的夏风3 小时前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
diygwcom3 小时前
electron-updater实现electron全量版本更新
前端·javascript·electron
volodyan3 小时前
electron react离线使用monaco-editor
javascript·react.js·electron