【JavaScript复习】【一篇就够】JavaScript事件循环知识题目全汇总

一、知识储备:

js的执行机制

        如下图:

js的事件循环:

  •         执行js代码的时候,遇见同步任务,直接推入调用栈中执行;
  •         遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中;
  •         当调用栈中的所有同步任务全部执行完成,将任务队列中的任务按顺序一个一个的推入并执行,重复执行这一系列的行为。

        过程如下图所示:

宏微队列及执行顺序        

宏微队列:

        异步任务又分为宏任务微任务

         宏任务:任务队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列。

        微任务:等宏任务中的主要功能都完成后,渲染引擎不急着去执行下一个宏任务,而是执行当前宏任务中的微任务。

常见的宏任务包含:

  • 执行script标签内部代码、
  • setTimeout/setInterval、
  • ajax请、
  • postMessageMessageChannel、
  • setImmediate,
  • I/O(Node.js)

常见的微任务包含:

  • Promise.then(); Promise.cath()、
  • async/await、
  • process.nextTick(Node.js)、
  • MutonObserver、
  • Object.observe(异步监视对象修改,已废弃)、
  • 加分回答 浏览器和Node 环境下,microtask 任务队列的执行时机不同 - Node端,microtask 在事件循环的各个阶段之间执行 - 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行

注意:1.new Promise()属于同步任务,但是Promise.then(); Promise.cath()属于异步任务的微任务。

           2.async函数里遇到await之前的代码是同步里的,遇到await时,会执行await后面的函数,然后返回一个promise,把await下面的代码放入微任务,并且退出这个async函数。

        3.resolved后的promise对象会在这该级别事件队列结束之后才开始执行,及执行与该轮微任务队列中,始于下一级别宏任务之前

执行顺序:

        1.先执行所有同步任务,遇到异步任务,将任务挂起,等到异步任务有返回之后推入到任务队列;

        2.同步任务执行完毕后,将任务队列中的任务按顺序一个一个的推入并执行;

        3.先执行任务队列里面所有的微任务,如果执行过程中又产生了微任务也会在本次执行过程中执行(即在下一个宏任务执行之前执行)

        4.每次准备取出一个宏任务执行前, 都要将所有的微任务一个一个取出来执行,也就是优先级比宏任务高,且与微任务所处的代码位置无关...依次类推到执行结束。

二、题目汇总:

        做完下面几道题目,js事件循环基本就没有问题了,可以说90%掌握吧

题目一:

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start') 
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')

结果如下:

script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout

详解

考察点 await上面的代码和后面的代码是直接执行的,await下面的代码是要进微任务队列的;new Promise()同步任务;resolve是同步执行的,then里的代码是要进微任务队列的

执行过程:script start->async1()->async1 start->async2->promise1->script end->微任务处理->async1 end->promise2->宏任务处理->settimeout

题目二:

console.log('1');
 
// 定义注解 setTimeout_1 用于下文使用方便
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})
 
// setTimeout_2
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
 
// 输出结果:  1 7 6 8 2 4 3 5 9 11 10 12

详解:

考察点 new Promise属于同步任务,nextTick放在微任务

执行过程:同步输出1-》同步new Promise 7-》宏任务之前先处理微任务-》6-》8-》第一个宏任务setTimeout-》2-》4-》setTimeout产生的微任务-》3-》5-》第二个setTimeout宏任务-》9-》11-》产生的微任务-》10-》12

题目三:

const promise = new Promise((resolve, reject) => {
    resolve("10")
  }).then(res => {
    console.log("res1:", res)    //res1: hahaha
    return 9
  }).then(res => {
    console.log("res2:", res)    //res2: 9
    return 8
  }).then(res => {
    console.log("res3:", res)    //res3: 8
    let promise2=new Promise((resolve,reject)=>{
        resolve("p2")
      }).then(res=>{
        console.log(res)
        setTimeout(function(){
          console.log("setTimeout2")
        },0)
      })
  })
  console.log('aaa')
  setTimeout(function(){
    console.log("setTimeout1")
  },0)
 
  const promise1 = new Promise((resolve, reject) => {
    console.log("p1")
    resolve(989)
}).then(res => {
    console.log(res)
    return 990
}).then(res=>{
  console.log(res)
  return 991
}).then(res=>{
  console.log(res)
  return 0
})
 
 
/*输出结果:
aaa
p1
res1: 10
989
res2: 9
990
res3: 8
991
p2
setTimeout1
setTimeout2
*/

详解:

考察点 resolved后的promise对象会在这该级别事件队列结束之后才开始执行,及执行与该轮微任务队列中,始于下一级别宏任务之前

执行过程:同步代码aaa-》p1-》宏任务之前把两个微任务处理掉-》res1 10-》989-》处理过程中继续产生微任务,继续处理-》res2 9-》990-》res 8-》991-》处理宏任务之前的微任务p2-》产生了一个宏任务setTimeout放到任务队列里-》执行宏任务,第一个setTimeout-》setTimeout1-》第二个setTimeout-》setTimeout2

题目四:

setTimeout(function () {
  console.log("set1");
  new Promise(function (resolve) {
    resolve();
  }).then(function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2");
  });
});
 
new Promise(function (resolve) {
  console.log("pr1");
  resolve();
}).then(function () {
  console.log("then1");
});
 
setTimeout(function () {
  console.log("set2");
});
 
console.log(2);
 
queueMicrotask(() => {
  console.log("queueMicrotask1")
});
 
new Promise(function (resolve) {
  resolve();
}).then(function () {
  console.log("then3");
});
 
 
 
结果
 
pr1
2
then1
queueMicrotask1
then3
set1
then2
then4
set2

详解:

考察点 queueMicrotask 来执行微任务,Window 或 Worker 接口的 queueMicrotask() 方法;别的,还需要说?

 执行过程: 

题目还有很多,但是,还需要吗? 

题做错了不要紧,记住下面几句话,再去试试

判断执行顺序大概以下几个重点:

1、promise中的回调函数立刻执行,then中的回调函数会推入微任务队列中,等待调用栈所有任务执行完才执行

2、async函数里遇到await之前的代码是同步里的,遇到await时,会执行await后面的函数,然后返回一个promise,把await下面的代码放入微任务,并且退出这个async函数。

3、调用栈执行完成后,会不断的轮询微任务队列,即使先将宏任务推入队列,也会先执行微任务

最后,如果你对前端技术感兴趣,对接下来该怎么学习感到迷茫和困惑。私信加群,或加我微信bao33449拉你进群,群内绝无任何营销,纯技术分享与交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值