【譯】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可能更容易。

相關文章
相關標籤/搜索