原文地址:JavaScript async/await: The Good Part, Pitfalls and How to Usejavascript
ES7经过介绍async/await
使得JavaScript的异步编程实现了重大改进。它提供了一种使用同步代码样式异步访问resoruces
的方式,并且不会阻塞主线程。然而,使用它有点棘手。在本文中,咱们将从不一样的角度探讨async/await
,并将展现如何正确有效地使用它们。java
async/await
给咱们带来的最重要的好处是同步编程风格。咱们来看一个例子吧。编程
async/await
版本比
promise
版本更容易理解。若是忽略
await
关键字,代码看起来就像任何其余同步语言,如Python。
好的一面不只是可读性,async/await
有本地浏览器支持。截至今天,全部主流浏览器 查看都彻底支持异步功能。promise
本机支持意味着您没必要转换代码。更重要的是,它有助于调试。当您在函数入口设置断点并跳过await
行时,您将看到调试器在bookModel.fetchAll()
执行期间暂停一段时间,而后移动到下一 行.filter
!这比promise
状况要容易得多,在promise
状况下你必须在.filter
行设置另外一个断点 。浏览器
async
关键字。它声明
getBooksByAuthorWithAwait()
函数返回值确保是一个
promise
,以便调用者能够安全调用
getBooksByAuthorWithAwait().then(...)
或
await getBooksByAuthorWithAwait()
。看看下面的代码(很差的作法!):
getBooksByAuthorWithPromise
能够返回一个
promise
(正常状况)或一个
null
值(例外状况),在这种状况下,调用者不能安全地调用
.then()
。经过
async
声明,这种返回
null
的状况将不可能出现。
有些文章将async/await
与Promise
进行比较,并声称它是JavaScript异步编程演变的下一代,我表示不一样意。Async/await
是一种改进,但它只不过是一种语法糖,它不会彻底改变咱们的编程风格。安全
从本质上讲,await
函数仍然是promise
。在正确使用await
函数以前,您必须了解promises
,还有就是,大多数状况下您须要同时使用promises
和异步函数。异步
考虑上面示例中的getBooksByAuthorWithAwait()
和getBooksByAuthorWithPromises()
函数。请注意,它们不只在功能上相同,并且具备彻底相同的接口。async
若是直接调用getBooksByAuthorWithAwait()
,这意味着将返回一个promise
。异步编程
嗯,这并非坏事。只是await
这个名称让人感受“哦,这能够将异步函数转换为同步函数”,这其实是错误的。函数
那么使用async/await
时会出现什么错误?如下一些常见的状况。
虽然await
可使您的代码看起来像同步,但请记住它们仍然是异步的,必须注意避免过于顺序。
await bookModel.fetchAll()
将等到fetchAll()
返回。await authorModel.fetch(authorId)
将被调用。 请注意,authorModel.fetch(authorId)
它不依赖于bookModel.fetchAll()
的结果,实际上它们能够并行调用!可是,经过await
在这里使用,这两个调用变为顺序,而且总执行时间将比并行版本长得多。这是正确的方法:
promise
:
await
。在复杂的工做流程中,直接使用
promises
可能更容易。
使用promises
,异步函数有两个可能的返回值:已解析的值和被拒绝的值。咱们能够.then()
用于正常状况,.catch()
用于特殊状况。可是,async/await
错误处理可能会很棘手。
最标准的(我推荐的)方法是使用try...catch
语句。当一个await
调用时,任何被拒绝的值都将做为异常抛出。这是一个例子:
catch
的错误正是被拒绝的值。在咱们发现异常后,有几种方法来处理它:
catch
块中使用任何return
语句,这等同于使用return undefined
,也是正常值。)throw error
,这在promise
链中容许使用async getBooksByAuthorWithAwait()
函数(即仍然能够像这样调用它getBooksByAuthorWithAwait().then(...).catch(error => ...)
); 或者可使用Error
对象包装错误,例如throw new Error(error)
,当控制台中显示此错误时,将提供完整的堆栈跟踪。return Promise.reject(error)
。这至关于throw error
不推荐。使用try...catch的好处是:
try...catch
块中包装多个await
调用在一个位置处理错误。这种方法也存在一个缺陷。因为try...catch
将捕获块中的每一个异常,所以将会捕获一些一般不会被promises
捕获的异常。想一想这个例子:
ReferenceError: cb is not defined
错误。错误是由
console.log()
输出而不是JavaScript自己。有时这多是致命的。若是
BookModel
被深深地包含在一系列函数调用中,而且其中一个调用吞噬了错误,那么找到这样的未定义错误将很是困难。
另外一种错误处理方式受Go语言的启发。它容许异步函数返回错误和结果。有关详细信息,请参阅此博客文章: How to write async await without try-catch blocks in Javascript
简言之,您可使用这样的await
函数:
咱们将在这里介绍的最后一种方法是继续使用 .catch()
。
回想一下await
的功能:它将等待promise
完成其工做。再回想一下,promise.catch()
也将是一个promise
,因此咱们能够像这样编写错误处理:
promises
和await
函数的混合体。您仍然须要了解promises
的工做原理。ES7引入的关键字async/await
确定是对JavaScript异步编程的改进。它可使代码更容易阅读和调试。然而,为了正确使用它们,必须彻底理解promise
,由于它们只不过是语法糖,而潜在的技术仍然是promise
。