1.async 和 defer,使用 async 要注意什么吗
async
和defer
都是用于在 HTML 中加载外部脚本的属性。
async
属性的作用是让脚本异步加载,不阻塞页面的渲染。当脚本加载完成后,会立即执行。使用async
的注意事项有:
- 脚本的执行顺序不确定:由于脚本是异步加载的,所以它们的执行顺序可能与在 HTML 中出现的顺序不同。如果多个脚本之间存在依赖关系,需要特别注意执行顺序的问题。
- 可能会在页面尚未完全加载时执行:如果脚本的执行依赖于页面的某些元素或状态,可能会出现问题。因为脚本可能在页面尚未完全加载时就执行了。
defer
属性的作用是让脚本延迟加载,在页面完全加载后再执行。脚本的执行顺序与在 HTML 中出现的顺序相同。
2. 事件循环
事件循环是 JavaScript 运行时的一种机制,用于处理异步任务和事件。它的主要作用是不断地检查任务队列,当有任务可执行时,就将其取出并执行。
事件循环的工作流程如下:
- 执行同步任务:JavaScript 引擎首先执行同步任务,即代码中按照顺序依次执行的任务。
- 检查任务队列:当同步任务执行完成后,JavaScript 引擎会检查任务队列中是否有可执行的异步任务。异步任务包括定时器、网络请求、事件处理等。
- 执行异步任务:如果任务队列中有可执行的异步任务,JavaScript 引擎会将其取出并执行。执行完成后,继续检查任务队列,重复这个过程。
事件循环使得 JavaScript 可以在不阻塞主线程的情况下处理异步任务,提高了程序的响应性和性能。
3. 宏队列细分为哪些队列
在 JavaScript 中,宏任务队列可以细分为以下几种队列:
- 定时器队列(Timer Queue):用于存储由
setTimeout()
和setInterval()
设置的定时器任务。 - I/O 队列(I/O Queue):用于存储由异步 I/O 操作(如文件读取、网络请求等)触发的任务。
- UI 渲染队列(UI Rendering Queue):用于存储与用户界面渲染相关的任务,如浏览器的重绘和回流操作。
当事件循环检查宏任务队列时,会按照队列的顺序依次取出任务并执行。不同类型的任务可能会在不同的队列中等待执行。
4、js 实现异步的方式有哪些,各个方式之间的区别
回调函数
- 这是最传统的异步实现方式。将一个函数作为参数传递给另一个函数,当异步操作完成后,调用这个回调函数来处理结果。
- 缺点是容易导致回调地狱,代码可读性和可维护性差。
Promise
- Promise 是一种更优雅的异步处理方式。它代表了一个异步操作的最终完成或失败,并提供了一种统一的接口来处理异步操作的结果。
- Promise 可以链式调用,避免了回调地狱的问题。同时,它还提供了
then
、catch
、finally
等方法来处理不同的状态。
async/await
- 这是基于 Promise 的语法糖,使异步代码看起来像同步代码一样。使用
async
关键字定义一个异步函数,在函数内部可以使用await
关键字等待一个 Promise 的结果。 - 大大提高了异步代码的可读性和可维护性,同时也更容易进行错误处理。
事件监听和发布 / 订阅模式
- 通过监听特定的事件,当异步操作完成后触发相应的事件,然后在事件处理函数中处理结果。
- 发布 / 订阅模式则是一种更通用的事件处理方式,允许不同的组件之间进行松耦合的通信。
继续阅读->