例子一
这里有一个例子,涉及到函数嵌套调用、微任务和宏任务。
function secondary() {
console.log('Inside secondary');
}
function primary() {
console.log('Start primary');
// 微任务:Promise
Promise.resolve().then(function promiseCallback() {
console.log('Promise Callback in primary');
});
console.log('End primary');
// 在末尾调用secondary函数
secondary();
}
console.log('Global start');
// 调用primary函数
primary();
console.log('Global end');
// 宏任务:setTimeout
setTimeout(function timeoutCallback() {
console.log('Timeout Callback');
}, 0);
执行以上代码时,会按照下面的步骤进行:
- 打印"Global start"。
- 开始执行primary函数。
- 在primary内部,打印"Start primary"。
- Promise.resolve().then(…)创建了一个微任务,将在当前宏任务(即primary函数)完成后执行。
- 打印"End primary"。
- 调用并执行secondary函数,打印"Inside secondary"。
- primary函数执行完毕,控制权返回到全局上下文。
- 打印"Global end"。
- 当前宏任务结束,开始执行微任务队列中的任务。
10 执行微任务,打印"Promise Callback in primary"。 - 微任务队列为空,事件循环移动到下一个宏任务。
- 执行由setTimeout(…, 0)排定的宏任务,打印"Timeout Callback"。
所以,程序的输出将会是:
Global start
Start primary
End primary
Inside secondary
Global end
Promise Callback in primary
Timeout Callback
这个例子清晰地展示了JavaScript事件循环中同步代码、微任务和宏任务的执行顺序。主要要点是,同步代码总是首先执行,微任务会在当前宏任务结束后执行,而新的宏任务会在所有微任务执行完毕后才开始执行。
例子2
function task() {
console.log('Performing a task...');
}
function complexFunction() {
console.log('Start of complexFunction');
// 微任务:通过Promise.then添加的回调
Promise.resolve().then(() => {
console.log('Promise resolved in complexFunction');
});
// 宏任务:通过setTimeout添加的回调
setTimeout(() => {
console.log('Timeout in complexFunction');
}, 0);
console.log('End of complexFunction');
// 在complexFunction结尾处调用task函数
task();
}
console.log('Script start');
// 调用 complexFunction
complexFunction();
console.log('Script end');
// 宏任务:全局 setTimeout 回调
setTimeout(() => {
console.log('Global timeout');
}, 0);
// 微任务:全局 Promise.then 回调
Promise.resolve().then(() => {
console.log('Global promise resolved');
});
执行这个脚本时代码的执行顺序将会如下:
- 打印"Script start"。
- 开始执行
complexFunction()
。 - 打印"Start of complexFunction"。
- 创建一个微任务(Promise resolved in complexFunction)。
- 创建一个宏任务(Timeout in complexFunction)。
- 打印"End of complexFunction"。
- 调用并且执行
task()
函数,打印"Performing a task…"。 complexFunction()
执行完毕,控制权返回到全局执行上下文。- 打印"Script end"。
- 当前宏任务结束,JavaScript运行时开始处理微任务队列。
- 执行微任务,打印"Promise resolved in complexFunction"。
- 执行微任务,打印"Global promise resolved"。
- 微任务队列为空,事件循环移动到下一个宏任务。
- 执行由
complexFunction
中的setTimeout
排定的宏任务,打印"Timeout in complexFunction"。 - 执行全局的
setTimeout
排定的宏任务,打印"Global timeout"。
所以,整个脚本的输出将会是:
Script start
Start of complexFunction
End of complexFunction
Performing a task...
Script end
Promise resolved in complexFunction
Global promise resolved
Timeout in complexFunction
Global timeout
这个例子提供了更详细的视角,帮助理解在复杂情况下,同步代码、微任务、宏任务之间的关系和执行顺序。
例子3
function log(message) {
console.log(message);
}
function processItem(item) {
log(`Processing item: ${item}`);
}
function complexOperation() {
log('Complex operation started');
setTimeout(() => {
log('Timeout 1 triggered');
Promise.resolve().then(() => log('Microtask 1 from Timeout 1'));
}, 0);
Promise.resolve().then(() => {
log('Microtask 1 triggered');
setTimeout(() => log('Timeout 2 from Microtask 1'), 0);
});
Promise.resolve().then(() => log('Microtask 2 triggered'));
log('Complex operation ended');
}
function executeSequence() {
log('Sequence started');
complexOperation();
log('Sequence continued');
processItem(1);
processItem(2);
log('Sequence ended');
}
log('Script start');
setTimeout(() => {
log('Global timeout triggered');
Promise.resolve().then(() => log('Microtask from Global timeout'));
}, 0);
executeSequence();
Promise.resolve().then(() => log('Global microtask triggered'));
log('Script end');
执行这段代码时,事件将按以下顺序发生:
- 打印"Script start"。
- 创建一个全局宏任务(Global timeout triggered)。
- 调用
executeSequence()
。 - 打印"Sequence started"。
- 调用
complexOperation()
。 - 打印"Complex operation started"。
- 创建一个宏任务(Timeout 1 triggered)。
- 创建第一个微任务(Microtask 1 triggered)。
- 创建第二个微任务(Microtask 2 triggered)。
- 打印"Complex operation ended"。
- 返回到
executeSequence()
并打印"Sequence continued"。 - 调用
processItem(1)
并打印"Processing item: 1"。 - 调用
processItem(2)
并打印"Processing item: 2"。 - 打印"Sequence ended"。
executeSequence()
执行完毕,控制权返回至全局上下文。- 打印"Script end"。
- 当前宏任务结束,开始处理微任务队列。
- 执行第一个微任务,打印"Microtask 1 triggered"并创建一个新宏任务(Timeout 2 from Microtask 1)。
- 执行第二个微任务,打印"Microtask 2 triggered"。
- 执行全局微任务,打印"Global microtask triggered"。
- 微任务队列清空,事件循环移动到下一个宏任务。
- 执行由
complexOperation
中的setTimeout
排定的宏任务(Timeout 1 triggered),打印"Timeout 1 triggered"并创建一个新微任务(Microtask 1 from Timeout 1)。 - 执行由第一个微任务中的
setTimeout
排定的宏任务(Timeout 2 from Microtask 1),打印"Timeout 2 from Microtask 1"。 - 执行全局
setTimeout
排定的宏任务(Global timeout triggered),打印"Global timeout triggered"并创建一个新微任务(Microtask from Global timeout)。 - 处理微任务队列:打印"Microtask 1 from Timeout 1"。
- 处理微任务队列:打印"Microtask from Global timeout"。
整个脚本的输出应该如下:
Script start
Sequence started
Complex operation started
Complex operation ended
Sequence continued
Processing item: 1
Processing item: 2
Sequence ended
Script end
Microtask 1 triggered
Microtask 2 triggered
Global microtask triggered
Timeout 1 triggered
Timeout 2 from Microtask 1
Global timeout triggered
Microtask 1 from Timeout 1
Microtask from Global timeout
此示例展示了嵌套函数调用与 JavaScript 事件循环中的微任务、宏任务之间复杂的交互。每一步都是按照 JavaScript 运行时的规则来执行的,同步代码总是首先执行,接着是微任务,最后是宏任务。在宏任务中添加的微任务会在当前宏任务完成后,在下一轮事件循环中先于其他宏任务执行。