ES6已经给前端开发带来了一些真正的变革,然而,ES7中引入的 async/await 更是前端工程师不容错过的一个有力工具。它看起来不是很惊人的东西,但是它对于代码清晰度,可重用性,代码组织以及错误处理都有着很大的影响。在这篇文章中,我们将详细介绍 async/await 的原理,帮助读者从理论上和实战经验上理解这项技术和如何使用它来提高代码的质量和开发速度。
async/await 的神奇原理
在介绍 async/await 的工作原理之前,我们首先需要理解 JavaScript 是如何处理异步请求的。当需要从服务器请求一些数据或执行一些操作时,我们不能让代码等待服务器的响应。因此,JavaScript 引入了 callback。这种模式允许在异步操作完成后被调用的函数作为参数传递给另一个函数的方式。这是 JavaScript 异步编程的基础。
尽管这种编程方式是很有用的,但是它带来了很多问题。由于 callback 链是在代码执行过程中动态创建的,因此难以理解和调试。出错时也难以追踪具体错误。
为了解决这个问题,Promise 出现了。Promise 是一个用于异步操作的对象,表示一个异步操作的结果。Promise 有三种状态:pending、fulfilled 和 rejected。当异步操作完成时,它提供了一个很好的方式来获取结果。由于 Promise 具有链式调用的属性,因此可以更轻松地理解和调试异步请求,而不是像 callback 那样深度嵌套。
async/await 则是 Promise 的进一步扩展。async/await 基于 Promise ,但是更易读、易用以及更类似于同步代码的编程风格。在函数前添加 async 关键字会将其转换为 Promise,并允许使用 await 来等待 Promise 解决。在异步操作完成后,await 表达式将 Promise 结果(或 Promise 解决值)返回,使 Promise 更加容易被组织和消费。
实现 async/await:示例代码
async function getUserData() { let userData = await fetch('/user-data') .then(res => res.json()); console.log(userData); } getUserData();
如上所示,我们定义了一个函数 getUserData()
,使用 async
关键字将其声明成一个异步函数。在函数主体中,我们用 await 关键字等待 fetch()
方法的结果。fetch()
是一个用于 AJAX 请求的函数。然后,我们将它的结果(Promise 对象)使用 .then()
方法进行解析,并将结果打印到控制台。注意,我们在调用函数时未传递任何参数。这是因为 getUserData()
函数调用之后返回一个 Promise 对象,然后在函数主体内使用 await
等待 Promise 对象的解决。由于该方法返回的 Promise 已经解决,因此在 console.log()
语句之前,我们可以直接访问返回的 userData
。
组合 async/await
一个神奇并非只由一种魔力而来。在实战中,我们需要掌握 async/await 与其他 JavaScript 特性的组合方式。在这里,我们介绍两个常用的组合方式:Promise.all
和 try/catch
区块。
Promise.all
Promise.all 是一个接收 Promise 对象数组作为其参数的函数,它等待所有 Promise 对象解决并返回一个结果数组。这是一个非常方便的函数,可以使用它们来并行执行多个 Promise 对象。结合 async/await 实际运用场景。
async function logTableData() { const [users, products] = await Promise.all([ fetch('/users').then(res => res.json()), fetch('/products').then(res => res.json()) ]); console.log('Users:', users); console.log('Products:', products); }
如上所示,我们定义了一个带有async关键字的异步函数 logTableData()
。函数主体中我们使用了 Promise.all()
,它将异步请求并行运行,将结果存储在一个数组中。在这个例子中,我们请求了两个不同的数据源,用户和产品列表,并等待两个请求都返回结果后,将解析数据压入两个单独变量中。然后我们可以按照任何方式使用这些变量。
try/catch 区块
在现代 Web 应用程序中,错误处理是一项非常重要的任务。Async/await 不仅可以使应用程序更容易理解和组织,而且还提供了一个更好的错误解决方案——try/catch 区块。使用 try/catch 区块可以避免以前其它方式可能带来的非常大的代码混乱譬如表单验证等等。
-- -------------------- ---- ------- ----- -------- ---------- - --- - ----- ---- - ----- -------------- -------- ------- ----- ---------------------------- ----- ---- - ----- ----------------- -------- ------- ----- ------------------------------- ----------------- ----- ---------------- - ----- ----- - ----------------- ----- ----------- ----- - -
如上所示,我们定义了一个带有 async 关键字的异步函数 save(data)
。在这个例子中,我们有可能会遇到两个异步请求错误。使用 try/catch 区块可以更好地处理这种情况,而不是使用回调或Promise.then()的链式请求。catch 区块将捕获所有在 try 区块中抛出的错误,从而更容易进行错误处理。
结论
在本文中,我们对 async/await 进行了详细介绍,并解释了为什么它应该成为现代 JavaScript 异步编程的首选方式。除了讨论 async/await 的神奇原理以外,我们还展示了 async/await 的实际示例,包括与其他 JavaScript 特性的组合方式——Promise.all 和 try/catch 区块。
使用 async/await,可以更清晰地组织代码,减少 JavaScript 中的“callback hell”,使错误处理更容易且代码更可读。虽然这种技术看起来很简单,但是深入了解和掌握它可以使你的代码更加优秀。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6720a6012e7021665e033bb1