async 和 await 是 (ES8) 引入的异步编程的语法糖,用于更方便地处理异步操作。基本原理:
当一个函数被声明为 async 函数时,它将始终返回一个 Promise 对象。
async 函数内部可以包含 await 表达式,这些表达式会暂停函数的执行,等待 Promise 解析为 resolved 状态,然后继续执行函数。
await 只能在 async 函数中使用。
await 表达式会暂停 async 函数的执行,等待 Promise 解析为 resolved 或 rejected 状态。在这个过程中,async 函数的控制权会返回给调用者,允许执行其他任务。
一旦 Promise 解析为 resolved 状态,await 表达式会返回 Promise 的结果值,然后 async 函数继续执行。如果 Promise 解析为 rejected 状态,await 会抛出一个异常,可以通过 try...catch 来捕获。
以下是一个简单的例子来说明 async 和 await 的原理:
async function example() { console.log("Start");
// await 暂停函数执行,等待 promise 解析
let result = await new Promise((resolve) => {
setTimeout(() => {
resolve("Async operation completed"); }, 2000); });
console.log(result);
console.log("End"); }
example();
在这个例子中,example 函数内部的 await 表达式会暂停函数执行,等待 setTimeout 的 Promise 在2秒后解析为 resolved。在这段等待的时间内,JavaScript 运行时可以执行其他任务。一旦 Promise 解析为 resolved,await 返回解析的结果,example 函数继续执行其余的部分。
===========================================================
async/await 使得异步代码看起来和编写同步代码非常相似,但实际上它们并不是通过同步的方式来实现异步的。async/await 的实现依赖于 JS的事件循环和 Promises。这里是如何做到看起来像同步代码的方式来执行异步操作的: JavaScript 事件循环和非阻塞行为 JavaScript 在单线程中运行,使用事件循环来处理异步操作,使得代码执行非阻塞。事件循环允许 JavaScript 在等待异步操作(如 I/O、网络请求、定时器等)完成时,继续执行其他任务,然后在异步操作完成后返回处理结果。
1.Promises 提供了一种处理异步操作结果的方法。一个 Promise 有三种状态:pending(等待中)、fulfilled(已成功)和 rejected(已失败)。通过 .then() 和 .catch() 方法,可以指定当 Promise 被解决(fulfilled 或 rejected)时应该执行的操作。
2.async/await 是基于 Promises 的语法糖,让异步代码的编写和阅读更接近同步代码的风格。当你在一个函数声明前加上 async 关键字时,你可以在这个函数内部使用 await 关键字来等待一个 Promise 解决。await 暂停 async 函数的执行,直到等待的 Promise 被解决,然后继续执行 async 函数的剩余部分。
代码清晰: 使用 async/await,异步代码的结构看起来更接近于同步代码,因为它避免了回调函数的嵌套,使得逻辑更直线、更易于理解和维护。
执行流程: 尽管 async/await 使得代码看起来像是按顺序执行的,实际上,每当执行到 await 表达式时,函数的执行就会暂停,控制权返回给事件循环,允许其他操作(如事件处理、其他异步操作)继续执行。一旦 await 后面的 Promise 解决,函数会从暂停的地方恢复执行。
结论 async/await 使得编写异步代码更加简洁和直观,它们通过在事件循环中合理安排任务执行的顺序,使得代码在逻辑上看起来像是同步执行,实际上仍然是非阻塞的异步执行。
当手写一个 Promise 时,我会考虑以下关键点:
1.Promise 状态管理:
2.Promise 有三个状态:pending(等待中)、fulfilled(已成功)和 rejected(已失败)。
3.Promise 的状态一旦改变就不会再变。
4.then 方法和链式调用:
5.then 方法是用来处理 Promise 的成功状态。
6.考虑链式调用,确保 then 方法返回一个新的 Promise 对象。
7.错误处理:
8.要有对错误状态的处理,通常通过 catch 方法或在 then 中的第二个参数进行错误处理。
9.catch 方法:
10.catch 方法用于处理 Promise 的 rejected 状态。
11.finally 方法:
12.finally 方法用于在 Promise 结束时执行一些代码,无论是成功还是失败。
13.异步操作的处理:
14.如果 Promise 内部包含异步操作,确保在异步操作完成时改变 Promise 的状态。
15.处理返回值:
16.then 方法中的回调函数可以返回一个值或一个 Promise。如果返回一个 Promise,则需要等待该 Promise 解决后再继续链式调用。
17.微任务队列:
18.考虑使用 queueMicrotask 或 Promise.resolve().then() 确保 then 方法中的回调函数以微任务的形式执行。
19.Promise 链的处理:
20.确保链式调用的每个 then 方法都能够正确处理前一个 Promise 的状态,并返回一个新的 Promise。
21.可迭代性:
22.考虑 Promise 对象是可迭代的,可以通过 Symbol.iterator 来实现。
23.返回对象的 then 方法:
24.考虑当 Promise 的返回对象中包含 then 方法时的处理。
Promise 的状态有几种:三种 pending fulfilled rejected
我:遍历,那个先个执行完就直接返回
面试官:怎么返回的啊
我:啥?
面试官:你写过 Promise.all,那 Promise.all 怎么返回的啊
我:新建一个数组,数组长度等于Promise 中传入数组的长度就返回啊
面试官:那是返回条件,怎么返回的(语气感觉有些急了)
我:resolve
面试官:失败那
我:reject
面试官:有些人只知道三种状态,但不知道怎么修改
我:不好意思,刚没获取到您想问的点
不知道,只知道是Generator函数的语法糖
Generator 了解多少
setTimeout
是一个基本的定时器函数,用于在一定时间后执行某个函数,没有处理异步流程的优雅机制。
Promise 是一种更高级的异步编程模式,提供了更好的结构和错误处理机制 .catch
async
/await
是建立在 Promise 基础之上的语法糖, 使得异步代码看起来更像同步代码,提高了可读性和可维护性。try..catch
在实际开发中,/ 的使用已经取代了大部分原本使用回调函数和 Promise 的异步代码,因为它提供了更简洁和直观的写法。async
await
执行栈用于存储当前执行的代码,而任务队列用于存储将来将要执行的任务。
Promise Jobs(微任务):当Promise被resolve或reject时,它产生的任务会被放入微任务队列。这样可以确保在同一轮事件循环中,Promise的状态变化能够被及时处理。
一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
宏任务:setTimeout、setInterval等宏任务产生的任务会被放入宏任务队列。
通过将微任务放在宏任务之前,可以确保微任务在下一个宏任务之前执行,从而提高了响应性能。这样,Promise的回调、MutationObserver等微任务能够在当前任务结束后立即执行,不必等待下一个宏任务。
这对于一些需要及时响应的场景(例如Promise的resolve/reject、用户交互等)非常重要,避免了不必要的延迟。
总体而言,微任务先于宏任务执行的机制是为了更好地处理异步操作,提高响应性能,确保某些异步操作在同一轮事件循环中得到及时执行