JS事件循环机制 面试题

深入理解JavaScript宏任务与微任务:异步执行顺序与发布/订阅模式
本文详细解释了JavaScript中的宏任务和微任务执行机制,包括script标签、定时器、Promise和异步函数等的执行顺序,并通过案例演示。同时介绍了手写订阅发布模式在处理事件中的应用。

1.宏任务和微任务(笔试题)

常见的宏任务包含:

  • 执行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.await之前的代码是同步里的,await执行后面的函数,然后返回一个promise,把await下面的代码放入微任务,并且退出这个async函数。

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

async function async1() {
  console.log('async1 start')	// 同步任务
  await async2() 	// await要等右边全部执行完毕才会进行下一步
  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

1.2.案例

setTimeout(() => {
	console.log(1);
}, 0);
new Promise((resolve, reject) => {
  console.log(2);
  resolve("p1");
  new Promise((resolve, reject) => {
    console.log(3);
    setTimeout(() => {
      resolve("setTimeout2");
      console.log(4);
    }, 0);
    resolve("p2");
  }).then(data => {
    console.log(data);
  })
  setTimeout(() => {
    resolve("setTimeout1");
    console.log(5);
  }, 0);
}).then(data => {
  console.log(data);
});
console.log(6);

执行结果

2 3 6 p2 p1 1 4 5

1.3.案例

console.log(11);
setTimeout(() => {
  console.log(12);
  let p = new Promise((resolve, reject) => {
    resolve(13);
  });
  p.then(data => {
    console.log(data);
  });
  console.log(15);
}, 0);
console.log(14);

 执行结果

11 14 12 15 13

1.4 先执行 宏任务当中的同步任务 --> 微任务当中的同步任务 --> 微任务当中的异步任务 --> 宏任务中的异步任务

  const handleClick = () => {

    console.log('iop');

    new Promise((resolve, reject) => {
      console.log('promise-1');

      setTimeout(() => {
        console.log('promise-timeeout');

      }, 0)
      process.nextTick(function () {
        console.log('promise---process.nextTick-1');
      })

      resolve('222')

    }).then((res) => {

      setTimeout(() => {
        console.log('promise-then-timeout');
      }, 0)
      console.log('promise-then');
      process.nextTick(function () {
        console.log('promise.then---process.nextTick-1');
      })
    })

    console.log('iop3333');

    setTimeout(() => {
      console.log('timeout-222');

    }, 0)

    process.nextTick(function () {
      console.log('process.nextTick-1');
    })


  }

 

2.手写订阅发布模式

// 发布订阅中心, on-订阅, off取消订阅, emit发布, 内部需要一个单独事件中心caches进行存储;
interface CacheProps {
  [key: string]: Array<((data?: unknown) => void)>;
}
class Observer {
  private caches: CacheProps = {}; // 事件中心
  on (eventName: string, fn: (data?: unknown) => void){ // eventName事件名-独一无二, fn订阅后执行的自定义行为
    this.caches[eventName] = this.caches[eventName] || [];
    this.caches[eventName].push(fn);
  }
  emit (eventName: string, data?: unknown) { // 发布 => 将订阅的事件进行统一执行
    if (this.caches[eventName]) {
      this.caches[eventName].forEach((fn: (data?: unknown) => void) => fn(data));
    }
  }
  off (eventName: string, fn?: (data?: unknown) => void) { // 取消订阅 => 若fn不传, 直接取消该事件所有订阅信息
    if (this.caches[eventName]) {
      const newCaches = fn ? this.caches[eventName].filter(e => e !== fn) : [];
      this.caches[eventName] = newCaches;
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

℡古壹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值