【译】JavaScript async / await:好的部分,陷阱和如何使用

async/await提供了一种使用同步样式代码异步访问资源的选项,而不会阻塞主线程。然而,使用它有点棘手。在本文中,咱们将从不一样的角度探讨async / await,并将展现如何正确有效地使用它们。编程

async / await的好处

async/await给咱们带来的最重要的好处是同步编程风格。咱们来看一个例子吧。promise

// async / await 
async getBooksByAuthorWithAwait(authorId){ const books = await bookModel.fetchAll(); return books.filter(b => b.authorId === authorId); } // promise 
getBooksByAuthorWithPromise(authorId){ return bookModel.fetchAll()。then( books => books.filter(b => b.authorId === authorId)); }

很明显,async/await版本比承诺版本更容易理解。安全

另外一个不太明显的好处是async关键字。它声明getBooksByAuthorWithAwait()函数返回值保证是一个promise,以便调用者能够调用getBooksByAuthorWithAwait().then(...)await getBooksByAuthorWithAwait()安全。想一想这个例子(很差的作法!):异步

getBooksByAuthorWithPromise(authorId){ if(!authorId){ return null; } return bookModel.fetchAll()。then( books => books.filter(b => b.authorId === authorId)); }

在上面的代码中,getBooksByAuthorWithPromise能够返回一个promise(正常状况)或一个null值(例外状况),在这种状况下,调用者不能.then()安全地调用  。而经过async声明,就能够安全的用.then()调用了。async

Async/await可能会产生误导

有些文章将async / await与Promise进行比较,并声称它是JavaScript异步编程演变的下一代,我不一样意。Async / await是一种改进,但它只不过是一种语法糖,它不会彻底改变咱们的编程风格。异步编程

从本质上讲,异步函数仍然是承诺。在正确使用异步函数以前,您必须了解promises,更糟糕的是,大多数状况下您须要使用promises和异步函数。函数

考虑上面示例中getBooksByAuthorWithAwait()getBooksByAuthorWithPromises()函数。请注意,它们不只在功能上相同,并且具备彻底相同的界面!fetch

getBooksByAuthorWithAwait()若是直接调用,这意味着将返回一个承诺。spa

嗯,这不必定是坏事。只有这个名字await让人感受“哦,这能够将异步函数转换为同步函数”,这其实是错误的。线程

Async/await陷阱

那么使用async/await时会出现什么错误这是一些常见的。

太顺序了

虽然await可使您的代码看起来像同步,但请记住它们仍然是异步的,必须注意避免过于顺序。

 

async getBooksAndAuthor(authorId){ const books = await bookModel.fetchAll(); const author = await authorModel.fetch(authorId); return { author, books:books.filter(book => book.authorId === authorId), }; }

此代码看起来逻辑正确。但这是错误的。

  1. await bookModel.fetchAll()将等到fetchAll()返回。
  2. 而后await authorModel.fetch(authorId)将被执行。

请注意,authorModel.fetch(authorId)它不依赖于bookModel.fetchAll()的结果,实际上它们能够并行调用!可是,在这里使用了await,这两个调用变为顺序,而且总执行时间将比并行版本长得多。

这是正确的方法:

async getBooksAndAuthor(authorId){ const bookPromise = bookModel.fetchAll(); const authorPromise = authorModel.fetch(authorId); const book = await bookPromise; const author = await authorPromise; return { author, books:books.filter(book => book.authorId === authorId), }; }

或者更糟糕的是,若是你想逐个获取一个项目列表,你必须依赖Promise:

 

async getAuthors(authorIds){ // 错误,这将致使顺序调用
  // const authors = _.map(
  // authorIds,
  // id => await authorModel.fetch(id)); // 正确
  const promises = _.map(authorIds,id => authorModel.fetch(id)); const authors = await Promise.all(promises); }

简而言之,您仍然须要异步考虑工做流,而后尝试await同步编写代码在复杂的工做流程中,直接使用promises可能更容易。

相关文章
相关标签/搜索