Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

readme.md

WTF JavaScript 极简教程 23. 事件循环

WTF JavaScript 教程,帮助新人快速入门 JavaScript。

推特@WTFAcademy_ | @0xAA_Science

WTF Academy 社群: 官网 wtf.academy | WTF Solidity 教程 | discord | 微信群申请

所有代码和教程开源在 github: github.com/WTFAcademy/WTF-Javascript


尽管 JavaScript 是单线程的编程语言,但是它可以通过事件循环机制处理并发操作,使 JavaScript 能够进行异步处理。JavaScript 将代码分为同步任务和异步任务,通过事件循环,异步任务在等待(如网络请求)期间不会阻塞主线程,可以同时执行其他任务。

调用栈和任务队列

在我们深入研究事件循环之前,我们需要理解以下两个概念:

  • 调用栈(Call Stack):JavaScript只有一个调用栈,用于在代码执行时跟踪函数调用的位置。当函数被调用时,它被添加到堆栈的顶部。当函数返回时,它从堆栈中被移除。同步任务会直接进入调用栈。

  • 任务队列(Task Queue):当异步任务(如setTimeout或fetch)完成时,它们的回调函数被添加到任务队列中。如果调用栈为空,事件循环会将这些回调函数一个接一个地移到调用栈中以便执行。

宏任务和微任务

在 JavaScript 的事件循环机制中,任务被分为两种类型:宏任务和微任务。

  • 宏任务(Macrotask):由 JavaScript 引擎线程直接执行的任务,包括整个脚本(main script),setTimeout 和 setInterval 的回调,setImmediate(Node.js环境)等。

  • 微任务(Microtask):微任务是在当前宏任务结束后立即执行的任务,包括 Promise 的 then 和 catch 的回调,process.nextTick(Node.js环境),MutationObserver的回调(浏览器环境)等。

事件循环过程

事件循环的过程可以简化为以下

几个步骤:

  1. 从宏任务队列中取出一个任务来执行。
  2. 执行完这个任务后,执行所有的微任务。
  3. 当微任务队列清空后,进入下一次事件循环,执行下一个宏任务。

来看一个例子,展示了宏任务和微任务的执行顺序:

console.log('script start');  // Macrotask

setTimeout(function() {
  console.log('setTimeout');  // Macrotask
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');  // Microtask
}).then(function() {
  console.log('promise2');  // Microtask
});

console.log('script end');  // Macrotask

上述代码的输出顺序为:

script start
script end
promise1
promise2
setTimeout

解释:

  1. 首先,代码执行到console.log('script start'),输出 "script start"。
  2. 然后,遇到setTimeout,将其回调函数推入宏任务队列中。
  3. 接着,遇到Promise.resolve().then(),将第一个then回调函数推入微任务队列中。
  4. 继续执行,遇到第二个then回调函数,将其推入微任务队列中。
  5. 执行到console.log('script end'),输出 "script end"。
  6. 当前宏任务(script主线程代码)执行完毕,事件循环开始处理微任务队列,按顺序执行微任务。
  7. 执行第一个微任务,输出 "promise1"。
  8. 执行第二个微任务,输出 "promise2"。
  9. 微任务执行完毕,事件循环开始处理下一个宏任务。
  10. 从宏任务队列中取出setTimeout的回调函数,输出 "setTimeout"。

建议你在 jsv9000 网站上体验一下事件循环的可视化,可以更直观的理解事件循环的过程。

总结

在这一讲,我们深入学习了 JavaScript 中的事件循环,包括宏任务和微任务。这是理解 JavaScript 异步编程的基础,能帮助我们更好地理解和控制代码的执行顺序。