Promise(微任务)和setTimeout(宏任务)的理解
Promise(微任务)和setTimeout(宏任务)的理解
Promise 和 setTimeout 是 JavaScript 中的两个不同概念,主要用于处理异步操作,但它们的用途和工作方式有所不同。
Promise
- 定义:Promise 是一个表示异步操作最终完成(或失败)及其结果值的对象。
- 用途:用于处理异步操作的结果,允许你在操作完成后执行某些代码(通过 .then() 和 .catch() 方法)。
- 状态:Promise 有三种状态:pending(进行中)、fulfilled(已完成)和 rejected(已拒绝)。
- 示例:
const myPromise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve("操作成功");
}, 1000);
});
myPromise.then(result => {
console.log(result); // 输出 "操作成功"
}).catch(error => {
console.error(error);
});
setTimeout
- 定义:setTimeout 是一个用于在指定的延迟后执行代码的函数
- 用途:用于创建延迟执行的操作,通常用于简单的定时任务。
- 返回值:返回一个定时器的 ID,可以用来取消定时器(使用 clearTimeout)。
- 示例:
setTimeout(() => {
console.log("1秒后执行");
}, 1000);
总结
- Promise 主要用于处理异步操作的结果,而 setTimeout 用于延迟执行某段代码。
- Promise 可以链式调用,便于处理多个异步操作的结果,而 setTimeout 只是简单的延迟执行。
事件循环与帧的关系
- 事件循环:
- JavaScript 是单线程的,意味着它一次只能执行一个任务。
- 事件循环负责管理执行栈、微任务队列和宏任务队列之间的调度。
- 帧的概念:
- 在浏览器中,帧(frame)通常指的是每次重绘(repaint)或重新渲染的周期。
- 一帧的时间通常是 16.67 毫秒(在 60 FPS 的情况下),这是浏览器更新页面的频率。
当前执行栈
- 栈的结构
- 当前执行栈是一个后进先出(LIFO, Last In First Out)的数据结构。
- 当一个函数被调用时,它会被推入栈中;当函数执行完毕后,它会从栈中弹出。
- 执行过程
- 当 JavaScript 引擎执行代码时,它会将全局上下文推入栈中。
- 当一个函数被调用时,新的执行上下文会被创建并推入栈中。
- 当函数执行完成后,它的上下文会被弹出,控制权会返回到调用该函数的上下文。
微任务
- 定义:微任务是指在当前执行栈完成后立即执行的任务。它们通常用于处理 Promise 的回调。
- 执行顺序:微任务会在当前宏任务完成后、下一个宏任务开始之前执行。也就是说,所有的微任务会在当前宏任务的所有代码执行完毕后立即执行。
- 常见的微任务:
- Promise 的 .then() 和 .catch() 回调
- MutationObserver 的回调
宏任务
- 定义:宏任务是指在事件循环中排队的任务,通常是较大的任务,可能会涉及到 I/O 操作、定时器等。
- 执行顺序:宏任务会在微任务执行完毕后执行。每次事件循环的迭代都会从宏任务队列中取出一个任务执行。
- 常见的宏任务:
- setTimeout
- setInterval
- I/O 操作(如网络请求)
事件循环的执行顺序
- 执行一个宏任务(例如,主线程中的代码)。
- 执行所有的微任务(例如,Promise 的回调)。
- 如果有下一个宏任务,继续执行下一个宏任务。
- 重复步骤 2 和 3,直到所有任务都完成。
也就是说Promise中的任务不会立即执行,而是在当前任务队列都执行完毕后才会执行,但是确实是在同一帧中执行的,若耗时过长也会卡进程。
而setTimeOut任务是把事件分发到下一帧去执行的,可以分帧执行减少每帧运行压力。