同步任务,宏任务,微任务
同步任务、宏任务和微任务属于 JavaScript 中的事件循环机制的问题。在 JavaScript 运行环境中,存在一个主线程和任务队列,所有代码都会被排入任务队列中。当主线程空闲时,它会从任务队列中取出一个任务并执行。而 JavaScript 中的任务可以分为同步任务、宏任务和微任务三种类型,它们在任务队列中的排列顺序不同。
同步任务是直接在主线程上执行的任务,按照顺序依次执行。
而宏任务和微任务则是异步执行的任务,会先被放入对应的任务队列中,等待主线程上的任务执行完毕后再去取出并执行宏任务和微任务。不同的是宏任务和微任务的执行顺序不同:
-
宏任务包括 setTimeout、setInterval、I/O、UI Rendering 等任务,会被放入宏任务队列中,等待主线程执行的同步任务执行完毕后,再去取出并执行宏任务队列中的任务。
-
微任务包括 Promise、process.nextTick、Object.observe、MutationObserver 等任务,会被放入微任务队列中,等待主线程执行的同步任务以及宏任务队列中的任务执行完毕后,再去取出并执行微任务队列中的任务。
因此,在 JavaScript 运行环境中,我们要了解事件循环机制以及同步任务、宏任务和微任务的执行顺序,才能正确地理解代码的执行过程和结果。
JavaScript 中任务的执行顺序如下:
-
执行同步任务,即按照顺序执行的任务。
-
执行当前宏任务队列中的一个任务,例如 setTimeout、setInterval、setImmediate 等。
-
执行所有可立即执行的微任务队列中的任务,例如 Promise、process.nextTick 等。
-
回到宏任务队列中,执行下一个宏任务,重复步骤 2 和 3。
JavaScript 中异步任务的执行顺序遵循任务队列机制。在一个事件循环周期中,可能存在多个宏任务(例如 setTimeout、setInterval 等),以及一个微任务队列(例如 Promise、process.nextTick 等)。每当一个宏任务执行完毕后,会依次从微任务队列中取出一个任务执行,直到所有的微任务都执行完毕;然后才会开始下一个宏任务的执行。
下面是一个代码示例,演示了上述执行顺序的过程:
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve(3).then(data => console.log(data));
})
Promise.resolve(4).then(data => console.log(data));
console.log(5);
这段代码的执行结果是:1 5 4 2 3。
解释如下:
- 执行同步任务,输出 1。
- 执行
setTimeout(() => {console.log(2);...})
,将回调函数放入宏任务队列中。 - 执行
Promise.resolve(4).then(data => console.log(data))
,将回调函数放入微任务队列中。 - 执行
console.log(5)
,输出 5。 - 执行微任务队列中的回调函数,输出 4。
- 取出宏任务队列中的回调函数并执行,输出 2。
- 执行
Promise.resolve(3).then(data => console.log(data))
,将回调函数放入微任务队列中。 - 执行微任务队列中的回调函数,输出 3。
需要注意的是,setTimeout 会将所在的函数加入到宏任务队列中,而 Promise.resolve.then 会将回调函数加入到微任务队列中。在遇到微任务队列时,必须要执行完所有的微任务,才会执行下一个宏任务。