嗨~👋 今天我们要一起深入探索JavaScript中的执行机制,这是每个前端开发者都需要掌握的魔法。
目录
[1. 同步执行:一步步的舞步](#1. 同步执行:一步步的舞步)
[2. 异步执行:自由的飞翔](#2. 异步执行:自由的飞翔)
[2.1 回调函数:古老的召唤术](#2.1 回调函数:古老的召唤术)
[2.2 Promises:愿望之珠](#2.2 Promises:愿望之珠)
[2.3 async/await:魔法师的咒语](#2.3 async/await:魔法师的咒语)
[3. 事件循环:舞会的指挥家](#3. 事件循环:舞会的指挥家)
[3.1 事件循环的具体过程](#3.1 事件循环的具体过程)
[3.1.1 调用栈(Call Stack)](#3.1.1 调用栈(Call Stack))
1. 同步执行:一步步的舞步
在JavaScript的世界里,同步执行就像是一场精心编排的舞蹈。每个舞步(代码)都按照顺序,一个接一个地进行。但如果某个舞步需要等待(比如等待音乐响起),整个舞池就会停下来等待,这可能会让舞会(用户体验)变得不那么流畅。
2. 异步执行:自由的飞翔
为了避免舞会的停滞,JavaScript引入了异步执行,就像是在舞池中自由飞翔。这样,即使有的舞步需要等待,其他的舞步也可以继续进行。
2.1 回调函数:古老的召唤术
在异步执行中,最古老的方法是使用"回调函数"。这是一种召唤术,你可以告诉舞池:"嘿,当我完成这个任务时,记得叫我哦!"然后你就可以去做其他事情了。
javascript
function asyncSplashWithCallback(splashCallback) {
setTimeout(() => {
splashCallback('跳进小溪的感觉真好!');
}, 1000);
}
asyncSplashWithCallback((message) => {
console.log(message);
});
2.2 Promises:愿望之珠
为了不让舞者们迷失在回调的迷宫中,JavaScript的巫师们创造了"Promises"------愿望之珠。这些珠子可以记住你的愿望,并在愿望实现时告诉你。
javascript
function asyncSplashWithPromise() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('跳进小溪的感觉真好!');
}, 1000);
});
}
asyncSplashWithPromise().then((message) => {
console.log(message);
});
2.3 async/await:魔法师的咒语
最后,最强大的魔法是"async/await"。这就像是魔法师的咒语,让你可以暂停等待,直到愿望实现,然后再继续你的魔法旅程。
javascript
async function asyncSplashWithMagic() {
const message = await asyncSplashWithPromise();
console.log(message);
}
asyncSplashWithMagic();
3. 事件循环:舞会的指挥家
在JavaScript的舞会中,有一位指挥家,那就是"事件循环"。它确保所有的舞步都能按照正确的顺序进行,无论是同步的还是异步的。
3.1 事件循环的具体过程
3.1.1 调用栈(Call Stack)
JavaScript代码执行时,首先进入的是调用栈。这是一个后进先出(LIFO)的数据结构,用来存储函数调用。
同步任务会立即执行,并将结果压入调用栈。
异步任务不会立即执行,而是将回调函数注册到消息队列中。
3.1.2事件队列(Event Queue)
事件队列是一个先进先出(FIFO)的数据结构,用来存储异步事件的回调函数。
当异步操作(如 setTimeout 、 Promise 、 requestAnimationFrame 等)完成时,它们的回调函数会被放入事件队列的末尾。
3.1.3 事件循环(Event Loop)
事件循环是JavaScript运行时的一部分,它不断地检查调用栈和事件队列。
如果调用栈为空,事件循环会从事件队列中取出第一个任务,将其压入调用栈执行。
这个过程会不断重复,直到调用栈和事件队列为空。
3.1.4 事件循环的具体步骤
- 执行同步代码:首先,执行所有的同步代码,这些代码会直接被压入调用栈。
- 执行异步回调:当同步代码执行完毕后,如果事件队列中有任务,事件循环会取出任务并压入调用栈执行。这个过程是循环进行的,直到事件队列为空。
- 处理宏任务和微任务,在JavaScript中,异步任务分为宏任务(Macro Tasks)和微任务(Micro Tasks)。宏任务包括: setTimeout 、 setInterval 、 I/O 、 UI渲染 等。微任务包括: Promise 回调、 MutationObserver 等。当调用栈清空后,事件循环会先执行所有微任务队列中的任务,然后再去检查宏任务队列。
- 宏任务和微任务的执行顺序,事件循环在处理完一个宏任务后,会先执行所有微任务队列中的回调,然后再去检查消息队列是否有新的宏任务。这意味着微任务的回调会在下一个宏任务之前执行。
代码示例
javascript
console.log('Script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('Script end');
输出顺序:
Script start
Script end
promise1
promise2
setTimeout
好啦,亲爱的朋友们,我们今天的JavaScript执行机制之旅就到这里啦!🚀 希望你们喜欢这次的探险,并且学到了一些新知识。理解JavaScript的执行机制是前端开发中非常基础且重要的技能,掌握它们可以让你在构建网页时更加得心应手。如果你有任何疑问,或者想要更多地了解这个话题,随时欢迎留言哦!我们下次再见啦!👋